<commit_before>var esprima = require('esprima');
var parser = require("sax").parser(true, {
    trim: true,
    xmlns: true,
    position: true
});
var fileUtils = require('./file-utils');

var systemVariables = ["_event", "_sessionid", "_name", "_ioprocessors", "_x"];

var scxmlAnalyzer = {
    analyze: function(currentScxml, docUrl, context) {
        var lastOpenScriptTagPosition, currentJsScriptTag, changes = [];

        var result = {
            errors: [],
            newScxml: null
        };

        var openNodeTypes = {
            "assign": function(node) {
                if (node.attributes.location && systemVariables.indexOf(node.attributes.location.value) !== -1) {
                    //If assignee is a system variable

                    createError({
                        message: 'You can\'t change system variables.'
                    });
                };

                if (node.attributes.expr) {
                    //If assign has a javascript expression

                    validateJavascriptExpression(node.attributes.expr.value, parser.startTagPosition - 1, parser.position);

                    //Construct variable = something; expression.
                    var constructedExpression = node.attributes.location.value + " = " + node.attributes.expr.value;

                    validateJavascriptExpression(constructedExpression, parser.startTagPosition - 1, parser.position);

                }
            },
            "script": function(node) {
                //Catch opening of script tag.
                lastOpenScriptTagPosition = parser.startTagPosition - 1;
            },
            "transition": function(node) {
                if (node.attributes.cond) {
                    //If condition has a javascript expression

                    validateJavascriptExpression(node.attributes.cond.value, parser.startTagPosition - 1, parser.position);
                }
            }
        };

        var closedNodeTypes = {
            "script": function() {

                if (parser.tag.isSelfClosing) {
                    //Self closing script tag means it is including another document
                    // if (parser.tag.attributes.src) {

                    //     //TODO fix async
                    //     getFileContents(parser.tag.attributes.src.value, function(fileContent) {
                    //         if (fileContent.error) {
                    //             var newError = {
                    //                 message: fileContent.error,
                    //                 start: parser.startTagPosition - 1,
                    //                 end: parser.position,
                    //                 line: parser.line,
                    //                 col: parser.column,
                    //                 oldScxml: currentScxml.substring(parser.startTagPosition - 1, parser.position)
                    //             };

                    //             createError(newError, true);
                    //         } else {
                    //             var oldScriptTag = currentScxml.substring(parser.startTagPosition - 1, parser.position);
                    //             var newScriptTag = '<script>' +
                    //                 '   ' + fileContent.content +
                    //                 '</script>';

                    //             currentScxml = currentScxml.replace(oldScriptTag, newScriptTag);
                    //         }
                    //     });
                    // }
                } else {
                    //Script has js in it's body

                    //Strip from <script></script> tags
                    var strippedJS = currentScxml.substring(lastOpenScriptTagPosition + 8, parser.position - 9);

                    var jsValidationResults = validateJavascriptExpression(strippedJS, lastOpenScriptTagPosition, parser.position);
                };

                //Reset to prevent future problems
                lastOpenScriptTagPosition = null;
            }
        };

        var treeTypes = {
            "BlockStatement": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "FunctionExpression": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "FunctionDeclaration": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "ExpressionStatement": function(tree) {
                tree = tree.expression;
                goThroughSyntaxTree(tree);
            },
            // "VariableDeclaration": function (tree) {

            // },
            "AssignmentExpression": function(tree) {
                    //Check if assignee is a system variable
                    if (systemVariables.indexOf(tree.left.name) !== -1) {

                        var newError = {
                            message: 'You can\'t change system variables.',
                            start: currentJsScriptTag.start,
                            end: currentJsScriptTag.end
                        };

                        createError(newError);
                    }
                }
                // ,
                // "ReturnStatement": function (tree) {

            // },
            // "CallExpression": function (tree) {

            // },
            // "IfStatement": function (tree) {

            // }
        };

        parser.onerror = function(e) {
            console.log(e);
        };

        parser.onopentag = function(node) {
            if (node.name && openNodeTypes[node.name]) {
                openNodeTypes[node.name](node);
            }
        };

        parser.onclosetag = function(node) {
            if (node && closedNodeTypes[node]) {
                closedNodeTypes[node]();
            }
        };

        parser.onend = function() {
            commitChanges();
        };

        function createError(error) {
            //Defaults
            error.changeType = "error";
            error.start = error.start || parser.startTagPosition - 1;
            error.end = error.end || parser.position;
            error.oldScxml = getContentBetween(error.start, error.end);
            error.message = (error.message || "") + ' At: ' + error.oldScxml;
            error.line = error.line || parser.line;
            error.col = error.col || parser.col;

            //TODO add reason to data.message of raise.
            if (error.addOnentry) {
                error.newScxml = '<onentry>\n   <raise event="error.execution"/>\n</onentry>';
            } else {
                error.newScxml = '<raise event="error.execution"/>';
            }

            changes.push(error);
        }

        function getContentBetween(start, end) {
            start = start || parser.startTagPosition - 1;
            end = end || parser.position;

            return currentScxml.substring(start, end);
        }

        //Removing content from a file more than once with indexof is a tricky thing.
        //I just took the shortcut and went with replace
        function commitChanges() {
            for (var i = changes.length - 1; i >= 0; i--) {
                    var newChange = changes[i];
                    if(newChange.changeType === "error") {
                        currentScxml = currentScxml.replace(newChange.oldScxml, newChange.newScxml);
                    } else if("replace") {

                    }
               };
            // var errors = result.errors;
            // for (var i = errors.length - 1; i >= 0; i--) {
            //     console.log(errors[i].message);
            //     currentScxml = currentScxml.replace(errors[i].oldScxml, errors[i].newScxml);
            // };

            // return result;
        }

        function validateJavascriptExpression(js, start, end) {

            currentJsScriptTag = {
                start: start,
                end: end
            };

            var analyzedJs;

            try {
                analyzedJs = esprima.parse(js, {});

                goThroughSyntaxTree(analyzedJs.body[0]);
            } catch (e) {

                var newError = {
                    message: 'Syntax error. ' + e.name + ': ' + e.message,
                    start: currentJsScriptTag.start,
                    end: currentJsScriptTag.end
                };

                createError(newError);
            }

            //Reset to prevent future problems
            currentJsScriptTag = null;
            return "";
        }

        function goThroughSyntaxTree(tree) {
            if (Array.isArray(tree)) {
                //Run each children of an array separately
                for (var i = tree.length - 1; i >= 0; i--) {
                    goThroughSyntaxTree(tree[i]);
                };
            } else if (tree.type && treeTypes[tree.type]) {
                //If we support the type value
                treeTypes[tree.type](tree);
            };
        }

        function getFileContents(filePath) {
            return fileUtils.read(filePath, docUrl, context);
        }

        parser.write(currentScxml).close();

        result.newScxml = currentScxml;
        return result;
    }
};

module.exports = scxmlAnalyzer;<commit_msg>Default validateJavascriptExpression parameters<commit_after>var esprima = require('esprima');
var parser = require("sax").parser(true, {
    trim: true,
    xmlns: true,
    position: true
});
var fileUtils = require('./file-utils');

var systemVariables = ["_event", "_sessionid", "_name", "_ioprocessors", "_x"];

var scxmlAnalyzer = {
    analyze: function(currentScxml, docUrl, context) {
        var lastOpenScriptTagPosition, currentJsScriptTag, changes = [];

        var result = {
            errors: [],
            newScxml: null
        };

        var openNodeTypes = {
            "assign": function(node) {
                if (node.attributes.location && systemVariables.indexOf(node.attributes.location.value) !== -1) {
                    //If assignee is a system variable

                    createError({
                        message: 'You can\'t change system variables.'
                    });
                };

                if (node.attributes.expr) {
                    //If assign has a javascript expression

                    validateJavascriptExpression(node.attributes.expr.value);

                    //Construct variable = something; expression.
                    var constructedExpression = node.attributes.location.value + " = " + node.attributes.expr.value;

                    validateJavascriptExpression(constructedExpression);

                }
            },
            "script": function(node) {
                //Catch opening of script tag.
                lastOpenScriptTagPosition = parser.startTagPosition - 1;
            },
            "transition": function(node) {
                if (node.attributes.cond) {
                    //If condition has a javascript expression

                    validateJavascriptExpression(node.attributes.cond.value);
                }
            }
        };

        var closedNodeTypes = {
            "script": function() {

                if (parser.tag.isSelfClosing) {
                    //Self closing script tag means it is including another document
                    // if (parser.tag.attributes.src) {

                    //     //TODO fix async
                    //     getFileContents(parser.tag.attributes.src.value, function(fileContent) {
                    //         if (fileContent.error) {
                    //             var newError = {
                    //                 message: fileContent.error,
                    //                 start: parser.startTagPosition - 1,
                    //                 end: parser.position,
                    //                 line: parser.line,
                    //                 col: parser.column,
                    //                 oldScxml: currentScxml.substring(parser.startTagPosition - 1, parser.position)
                    //             };

                    //             createError(newError, true);
                    //         } else {
                    //             var oldScriptTag = currentScxml.substring(parser.startTagPosition - 1, parser.position);
                    //             var newScriptTag = '<script>' +
                    //                 '   ' + fileContent.content +
                    //                 '</script>';

                    //             currentScxml = currentScxml.replace(oldScriptTag, newScriptTag);
                    //         }
                    //     });
                    // }
                } else {
                    //Script has js in it's body

                    //Strip from <script></script> tags
                    var strippedJS = currentScxml.substring(lastOpenScriptTagPosition + 8, parser.position - 9);

                    var jsValidationResults = validateJavascriptExpression(strippedJS, lastOpenScriptTagPosition, parser.position);
                };

                //Reset to prevent future problems
                lastOpenScriptTagPosition = null;
            }
        };

        var treeTypes = {
            "BlockStatement": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "FunctionExpression": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "FunctionDeclaration": function(tree) {
                tree = tree.body;
                goThroughSyntaxTree(tree);
            },
            "ExpressionStatement": function(tree) {
                tree = tree.expression;
                goThroughSyntaxTree(tree);
            },
            // "VariableDeclaration": function (tree) {

            // },
            "AssignmentExpression": function(tree) {
                    //Check if assignee is a system variable
                    if (systemVariables.indexOf(tree.left.name) !== -1) {

                        var newError = {
                            message: 'You can\'t change system variables.',
                            start: currentJsScriptTag.start,
                            end: currentJsScriptTag.end
                        };

                        createError(newError);
                    }
                }
                // ,
                // "ReturnStatement": function (tree) {

            // },
            // "CallExpression": function (tree) {

            // },
            // "IfStatement": function (tree) {

            // }
        };

        parser.onerror = function(e) {
            console.log(e);
        };

        parser.onopentag = function(node) {
            if (node.name && openNodeTypes[node.name]) {
                openNodeTypes[node.name](node);
            }
        };

        parser.onclosetag = function(node) {
            if (node && closedNodeTypes[node]) {
                closedNodeTypes[node]();
            }
        };

        parser.onend = function() {
            commitChanges();
        };

        function createError(error) {
            //Defaults
            error.changeType = "error";
            error.start = error.start || parser.startTagPosition - 1;
            error.end = error.end || parser.position;
            error.oldScxml = getContentBetween(error.start, error.end);
            error.message = (error.message || "") + ' At: ' + error.oldScxml;
            error.line = error.line || parser.line;
            error.col = error.col || parser.col;

            //TODO add reason to data.message of raise.
            if (error.addOnentry) {
                error.newScxml = '<onentry>\n   <raise event="error.execution"/>\n</onentry>';
            } else {
                error.newScxml = '<raise event="error.execution"/>';
            }

            changes.push(error);
        }

        function getContentBetween(start, end) {
            start = start || parser.startTagPosition - 1;
            end = end || parser.position;

            return currentScxml.substring(start, end);
        }

        //Removing content from a file more than once with indexof is a tricky thing.
        //I just took the shortcut and went with replace
        function commitChanges() {
            for (var i = changes.length - 1; i >= 0; i--) {
                    var newChange = changes[i];
                    if(newChange.changeType === "error") {
                        currentScxml = currentScxml.replace(newChange.oldScxml, newChange.newScxml);
                    } else if("replace") {

                    }
               };
        }

        function validateJavascriptExpression(js, start, end) {
            start = start || parser.startTagPosition - 1;
            end = end || parser.position;

            currentJsScriptTag = {
                start: start,
                end: end
            };

            var analyzedJs;

            try {
                analyzedJs = esprima.parse(js, {});

                goThroughSyntaxTree(analyzedJs.body[0]);
            } catch (e) {

                var newError = {
                    message: 'Syntax error. ' + e.name + ': ' + e.message,
                    start: currentJsScriptTag.start,
                    end: currentJsScriptTag.end
                };

                createError(newError);
            }

            //Reset to prevent future problems
            currentJsScriptTag = null;
            return "";
        }

        function goThroughSyntaxTree(tree) {
            if (Array.isArray(tree)) {
                //Run each children of an array separately
                for (var i = tree.length - 1; i >= 0; i--) {
                    goThroughSyntaxTree(tree[i]);
                };
            } else if (tree.type && treeTypes[tree.type]) {
                //If we support the type value
                treeTypes[tree.type](tree);
            };
        }

        function getFileContents(filePath) {
            return fileUtils.read(filePath, docUrl, context);
        }

        parser.write(currentScxml).close();

        result.newScxml = currentScxml;
        return result;
    }
};

module.exports = scxmlAnalyzer;<|endoftext|>


<commit_before>import React, { Component } from 'react';

import {
  FieldContainer,
  FieldLabel,
  FieldInput,
} from '@keystonejs/ui/src/primitives/fields';
// TODO: Upload component?
import { Input } from '@keystonejs/ui/src/primitives/forms';

export default class FileField extends Component {
  onChange = event => {
    const { field, onChange } = this.props;
    // TODO: File upload
    onChange(field, event.target.value);
  };
  render() {
    const { autoFocus, field, item } = this.props;
    const value = item[field.path] || '';
    return (
      <FieldContainer>
        <FieldLabel>{field.label}</FieldLabel>
        <FieldInput>
          <Input
            autocomplete="off"
            autoFocus={autoFocus}
            type="file"
            value={value}
            onChange={this.onChange}
          />
        </FieldInput>
      </FieldContainer>
    );
  }
}
<commit_msg>Fix DOM error for File input type<commit_after>import React, { Component } from 'react';

import {
  FieldContainer,
  FieldLabel,
  FieldInput,
} from '@keystonejs/ui/src/primitives/fields';
// TODO: Upload component?
import { Input } from '@keystonejs/ui/src/primitives/forms';

export default class FileField extends Component {
  onChange = event => {
    const { field, onChange } = this.props;
    // TODO: File upload
    onChange(field, event.target.value);
  };
  render() {
    const { autoFocus, field, item } = this.props;
    const value = item[field.path] || '';
    return (
      <FieldContainer>
        <FieldLabel>{field.label}</FieldLabel>
        <FieldInput>
          <Input
            autocomplete="off"
            autoFocus={autoFocus}
            type="file"
            onChange={this.onChange}
          />
        </FieldInput>
      </FieldContainer>
    );
  }
}
<|endoftext|>


<commit_before>define(
  'ephox.alloy.spec.InputSpec',

  [
    'ephox.alloy.alien.EventRoot',
    'ephox.alloy.api.SystemEvents',
    'ephox.alloy.api.behaviour.Representing',
    'ephox.alloy.construct.EventHandler',
    'ephox.boulder.api.FieldSchema',
    'ephox.boulder.api.Objects',
    'ephox.boulder.api.ValueSchema',
    'ephox.compass.Arr',
    'ephox.highway.Merger',
    'ephox.perhaps.Option',
    'ephox.scullion.Cell',
    'ephox.sugar.api.Value'
  ],

  function (EventRoot, SystemEvents, Representing, EventHandler, FieldSchema, Objects, ValueSchema, Arr, Merger, Option, Cell, Value) {
    // This is not fleshed out yet.
    var schema = ValueSchema.objOf([
      FieldSchema.defaulted('classes', [ ]),
      FieldSchema.option('value'),
      FieldSchema.option('placeholder'),
      FieldSchema.defaulted('type', 'input'),
      FieldSchema.defaulted('tag', 'input'),
      FieldSchema.defaulted('tabstop', true),

      FieldSchema.state('holdingValue', function () { return Cell(Option.none()); })
    ]);

    var make = function (spec) {
      var detail = ValueSchema.asStructOrDie('input.spec', schema, spec);

      var toProp = function (opt, name) {
        return opt.map(function (v) {
          // FIX: ItemData.value
          return [ { key: name, value: v.text } ];
        }).getOr([ ]);
      };

      return Merger.deepMerge({
        uiType: 'custom',
        // Simplify this
        dom: Objects.wrapAll(
          Arr.flatten([
            toProp(detail.value(), 'value'),
            [
              { key: 'tag', value: detail.tag() },
              {
                key: 'attributes',
                value: Objects.wrapAll(
                  Arr.flatten([
                    toProp(detail.placeholder(), 'placeholder'),
                    [ { key: 'type', value: detail.type() }]
                  ])
                )
              }
            ]
          ])
        ),

        representing: {
          query: function (comp) {
            var text = Value.get(comp.element());

            return detail.holdingValue().get().fold(function () {
              return { value: text, text: text };
            }, function (data) {
              return data.text === text ? data : { value: text, text: text };
            });
          },
          set: function (comp, value) {
            detail.holdingValue().set(Option.some(value));
            Value.set(comp.element(), value.text);
          }
        },

        tabstopping: detail.tabstop(),
        focusing: {
          onFocus: function (component) {
            var input = component.element();
            var value = Value.get(input);
            input.dom().setSelectionRange(0, value.length);
          }
        },

        events: Objects.wrapAll([
          {
            key: SystemEvents.systemInit(),
            value: EventHandler.nu({
              run: function (typeahead, simulatedEvent) {
                if (EventRoot.isSource(typeahead, simulatedEvent)) {
                  detail.value().each(function (value) {
                    Representing.setValue(typeahead, value);
                  });
                }
              }
            })
          }

        ])
      }, spec);
    };

    return {
      make: make
    };
  }
);<commit_msg>VAN-44-wheel-hackery-apis: explanatory comment<commit_after>define(
  'ephox.alloy.spec.InputSpec',

  [
    'ephox.alloy.alien.EventRoot',
    'ephox.alloy.api.SystemEvents',
    'ephox.alloy.api.behaviour.Representing',
    'ephox.alloy.construct.EventHandler',
    'ephox.boulder.api.FieldSchema',
    'ephox.boulder.api.Objects',
    'ephox.boulder.api.ValueSchema',
    'ephox.compass.Arr',
    'ephox.highway.Merger',
    'ephox.perhaps.Option',
    'ephox.scullion.Cell',
    'ephox.sugar.api.Value'
  ],

  function (EventRoot, SystemEvents, Representing, EventHandler, FieldSchema, Objects, ValueSchema, Arr, Merger, Option, Cell, Value) {
    // This is not fleshed out yet.
    var schema = ValueSchema.objOf([
      FieldSchema.defaulted('classes', [ ]),
      FieldSchema.option('value'),
      FieldSchema.option('placeholder'),
      FieldSchema.defaulted('type', 'input'),
      FieldSchema.defaulted('tag', 'input'),
      FieldSchema.defaulted('tabstop', true),

      FieldSchema.state('holdingValue', function () { return Cell(Option.none()); })
    ]);

    var make = function (spec) {
      var detail = ValueSchema.asStructOrDie('input.spec', schema, spec);

      var toProp = function (opt, name) {
        return opt.map(function (v) {
          // FIX: ItemData.value
          return [ { key: name, value: v.text } ];
        }).getOr([ ]);
      };

      return Merger.deepMerge({
        uiType: 'custom',
        // Simplify this
        dom: Objects.wrapAll(
          Arr.flatten([
            toProp(detail.value(), 'value'),
            [
              { key: 'tag', value: detail.tag() },
              {
                key: 'attributes',
                value: Objects.wrapAll(
                  Arr.flatten([
                    toProp(detail.placeholder(), 'placeholder'),
                    [ { key: 'type', value: detail.type() }]
                  ])
                )
              }
            ]
          ])
        ),

        representing: {
          query: function (comp) {
            var text = Value.get(comp.element());

            // Default the first ones.
            return detail.holdingValue().get().fold(function () {
              return { value: text, text: text };
            }, function (data) {
              return data.text === text ? data : { value: text, text: text };
            });
          },
          set: function (comp, value) {
            detail.holdingValue().set(Option.some(value));
            Value.set(comp.element(), value.text);
          }
        },

        tabstopping: detail.tabstop(),
        focusing: {
          onFocus: function (component) {
            var input = component.element();
            var value = Value.get(input);
            input.dom().setSelectionRange(0, value.length);
          }
        },

        events: Objects.wrapAll([
          {
            key: SystemEvents.systemInit(),
            value: EventHandler.nu({
              run: function (simulated, simulatedEvent) {
                if (EventRoot.isSource(simulated, simulatedEvent)) {
                  detail.value().each(function (value) {
                    Representing.setValue(simulated, value);
                  });
                }
              }
            })
          }

        ])
      }, spec);
    };

    return {
      make: make
    };
  }
);<|endoftext|>


<commit_before><commit_msg>removed unnecessary code<commit_after><|endoftext|>


<commit_before>import { UPDATE_ROOT } from '../actions/update_root_action';

const intialState = {
  currentRoot: '',
};

const root = (state = intialState, action) => {
  switch (action.type) {
    case UPDATE_ROOT:
      return {
        ...state,
        currentRoot: action.payload,
      };
    default:
      return state;
  }
};

export default root;
<commit_msg>Update name of root to currentRoot<commit_after>import { UPDATE_ROOT } from '../actions/update_root_action';

const intialState = {
  currentRoot: '',
};

const currentRoot = (state = intialState, action) => {
  switch (action.type) {
    case UPDATE_ROOT:
      return {
        ...state,
        currentRoot: action.payload,
      };
    default:
      return state;
  }
};

export default currentRoot;
<|endoftext|>


<commit_before>var async = require('async'),
	request = require('request'),
	assembleGadget = require('./factory').assembleGadget,
	error = require('../lib/error');

module.exports = assembleGadget({
	name: 'Gcal',
	account: 'Google',
	uri: 'https://www.google.com/calendar/',
	update: function(app, callback) {
		var account = this.user.accounts.google,
			that = this;

		var tasks = [ ];

		//Request new access token after expiry
		if (account.expires <= new Date) {
			tasks.push(function(callback) {
				var google = require('../accounts/google');

				google.refresh(app, account.refresh_token, function(err, result) {
					if (error(err, callback)) return;

					//Store new token; it will later be saved together with all other user data
					for (var key in result) {
						that.user.accounts.google[key] = result[key];
					}

					account = that.user.accounts.google;

					callback();
				})
			});
		}

		//Update calendar list every 24h
		if (!this.data.calendars ||
			+new Date - this.data.lastCalendarUpdate >= 24 * 60 * 60 * 1000)
		{
			tasks.push(updateCalendars);
		}

		//Check each calendar for events
		tasks.push(checkForEvents);

		async.waterfall(tasks, callback);

		function updateCalendars(callback) {
			request({
				url: 'https://www.googleapis.com/calendar/v3/users/me/calendarList',
				qs: {
					minAccessRole: 'reader',
					access_token: account.token
				},
				strictSSL: true
			}, function(err, res, body) {
				if (error(err, res, callback)) return;

				try {
					//Parse calendar list
					var doc = JSON.parse(body);
					that.data.calendars = [ ];

					for (var i = 0; i < doc.items.length; i++) {
						that.data.calendars.push(doc.items[i].id);
					}

					that.data.lastCalendarUpdate = new Date;

					callback();
				} catch (err) {
					error(err, res, callback);
				}
			});
		}

		function isToday(dateString) {
			//Extract timezone from ISO 8601 date string
			var timezone = /(([+-])(\d\d):(\d\d)|Z)$/.exec(dateString),
				offset = 0;

			//If not UTC, compute offset in minutes
			if (timezone[0] !== 'Z') {
				offset = parseInt(timezone[3]) * 60 + parseInt(timezone[4]);

				if (timezone[2] === '-') {
					offset = -offset;
				}
			}

			//Add local timezone offset
			offset += new Date().getTimezoneOffset();

			var serverNow = new Date;

			//Determine local time
			localNow = new Date(+serverNow + offset * 60 * 1000);

			//Determine local day start in server time
			var localDayStart = new Date(+serverNow -
				localNow.getHours() * 60 * 60 * 1000 -
				localNow.getMinutes() * 60 * 1000 -
				localNow.getSeconds() * 1000 -
				localNow.getMilliseconds());

			//Determine local day end in server time
			var localDayEnd = new Date(+localDayStart + 24 * 60 * 60 * 1000);

			//Parse local date (and thereby convert to server time)
			var localDate = new Date(dateString);

			//Check if given date is local today
			return localDate >= localDayStart &&
				localDate <= localDayEnd;
		}

		function checkForEvents(callback) {
			//We do not know the calendar's timezone, so we initially
			//look for all events in UTC-12 to UTC+14.
			//toISOString() returns the date in UTC, so we don't have to
			//worry about the server timezone.
			var start = new Date;
			start.setHours(0);
			start.setMinutes(0);
			start = new Date(+start - 14 * 60 * 60 * 1000);

			var end = new Date(+start + 50 * 60 * 60 * 1000);

			//Request events from every calendar
			async.map(that.data.calendars, function(calendarId, callback) {
				request({
					url: 'https://www.googleapis.com/calendar/v3/calendars/' +
						calendarId + '/events',
					qs: {
						timeMin: start.toISOString(),
						timeMax: end.toISOString(),
						access_token: account.token
					},
					strictSSL: true
				}, function(err, res, body) {
					if (error(err, res, callback)) return;

					try {
						//Parse response
						var doc = JSON.parse(body),
							events = 0;

						//Count today's events
						for (var i = 0; i < doc.items.length; i++) {
							//Events spanning multiple days only have
							//start.date and end.date set
							if (doc.items[i].start.dateTime &&
								doc.items[i].start.dateTime &&
								(isToday(doc.items[i].start.dateTime) ||
								isToday(doc.items[i].end.dateTime)))
							{
								events++;
							}
						}

						callback(null, events);
					} catch (err) {
						error(err, res, callback, true);
					}
				});
			}, function(err, results) {
				if (error(err, callback)) return;

				//Sum up today's events from all calendars
				var totalEvents = 0;

				for (var i = 0; i < results.length; i++) {
					totalEvents += results[i];
				}

				callback(null, { value: totalEvents });
			});
		}
	},
	checkAvailability: function(app, callback) {
		var token = this.user.accounts.google.token;

		request({
			url: 'https://www.googleapis.com/calendar/v3/users/me/calendarList',
			qs: {
				minAccessRole: 'reader',
				access_token: token
			},
			strictSSL: true
		}, function(err, res, body) {
			if (err) return callback(false);

			if (res.statusCode !== 200) {
				return callback(false);
			}

			try {
				//Parse calendar list
				var doc = JSON.parse(body);
				callback(doc.items.length > 0);
			} catch (err) {
				callback(false);
			}
		});
	},
	intervals: [
		          5 * 60,            30, //5m after login, update every 30s
		     3 * 60 * 60,       10 * 60, //3h after login, update every 10m
		    24 * 60 * 60,       30 * 60, //1d after login, update every 30m
		7 * 24 * 60 * 60,   5 * 60 * 60 // 1w after login, update every 5h
	]
});<commit_msg>Added extra caution for cancelled events that might have no time<commit_after>var async = require('async'),
	request = require('request'),
	assembleGadget = require('./factory').assembleGadget,
	error = require('../lib/error');

module.exports = assembleGadget({
	name: 'Gcal',
	account: 'Google',
	uri: 'https://www.google.com/calendar/',
	update: function(app, callback) {
		var account = this.user.accounts.google,
			that = this;

		var tasks = [ ];

		//Request new access token after expiry
		if (account.expires <= new Date) {
			tasks.push(function(callback) {
				var google = require('../accounts/google');

				google.refresh(app, account.refresh_token, function(err, result) {
					if (error(err, callback)) return;

					//Store new token; it will later be saved together with all other user data
					for (var key in result) {
						that.user.accounts.google[key] = result[key];
					}

					account = that.user.accounts.google;

					callback();
				})
			});
		}

		//Update calendar list every 24h
		if (!this.data.calendars ||
			+new Date - this.data.lastCalendarUpdate >= 24 * 60 * 60 * 1000)
		{
			tasks.push(updateCalendars);
		}

		//Check each calendar for events
		tasks.push(checkForEvents);

		async.waterfall(tasks, callback);

		function updateCalendars(callback) {
			request({
				url: 'https://www.googleapis.com/calendar/v3/users/me/calendarList',
				qs: {
					minAccessRole: 'reader',
					access_token: account.token
				},
				strictSSL: true
			}, function(err, res, body) {
				if (error(err, res, callback)) return;

				try {
					//Parse calendar list
					var doc = JSON.parse(body);
					that.data.calendars = [ ];

					for (var i = 0; i < doc.items.length; i++) {
						that.data.calendars.push(doc.items[i].id);
					}

					that.data.lastCalendarUpdate = new Date;

					callback();
				} catch (err) {
					error(err, res, callback);
				}
			});
		}

		function isToday(dateString) {
			//Extract timezone from ISO 8601 date string
			var timezone = /(([+-])(\d\d):(\d\d)|Z)$/.exec(dateString),
				offset = 0;

			//If not UTC, compute offset in minutes
			if (timezone[0] !== 'Z') {
				offset = parseInt(timezone[3]) * 60 + parseInt(timezone[4]);

				if (timezone[2] === '-') {
					offset = -offset;
				}
			}

			//Add local timezone offset
			offset += new Date().getTimezoneOffset();

			var serverNow = new Date;

			//Determine local time
			localNow = new Date(+serverNow + offset * 60 * 1000);

			//Determine local day start in server time
			var localDayStart = new Date(+serverNow -
				localNow.getHours() * 60 * 60 * 1000 -
				localNow.getMinutes() * 60 * 1000 -
				localNow.getSeconds() * 1000 -
				localNow.getMilliseconds());

			//Determine local day end in server time
			var localDayEnd = new Date(+localDayStart + 24 * 60 * 60 * 1000);

			//Parse local date (and thereby convert to server time)
			var localDate = new Date(dateString);

			//Check if given date is local today
			return localDate >= localDayStart &&
				localDate <= localDayEnd;
		}

		function checkForEvents(callback) {
			//We do not know the calendar's timezone, so we initially
			//look for all events in UTC-12 to UTC+14.
			//toISOString() returns the date in UTC, so we don't have to
			//worry about the server timezone.
			var start = new Date;
			start.setHours(0);
			start.setMinutes(0);
			start = new Date(+start - 14 * 60 * 60 * 1000);

			var end = new Date(+start + 50 * 60 * 60 * 1000);

			//Request events from every calendar
			async.map(that.data.calendars, function(calendarId, callback) {
				request({
					url: 'https://www.googleapis.com/calendar/v3/calendars/' +
						calendarId + '/events',
					qs: {
						timeMin: start.toISOString(),
						timeMax: end.toISOString(),
						access_token: account.token
					},
					strictSSL: true
				}, function(err, res, body) {
					if (error(err, res, callback)) return;

					try {
						//Parse response
						var doc = JSON.parse(body),
							events = 0;

						//Count today's events
						for (var i = 0; i < doc.items.length; i++) {
							//Events spanning multiple days only have
							//start.date and end.date set
							if (doc.items[i].start &&
								doc.items[i].end &&
								doc.items[i].start.dateTime &&
								doc.items[i].start.dateTime &&
								(isToday(doc.items[i].start.dateTime) ||
								isToday(doc.items[i].end.dateTime)))
							{
								events++;
							}
						}

						callback(null, events);
					} catch (err) {
						error(err, res, callback, true);
					}
				});
			}, function(err, results) {
				if (error(err, callback)) return;

				//Sum up today's events from all calendars
				var totalEvents = 0;

				for (var i = 0; i < results.length; i++) {
					totalEvents += results[i];
				}

				callback(null, { value: totalEvents });
			});
		}
	},
	checkAvailability: function(app, callback) {
		var token = this.user.accounts.google.token;

		request({
			url: 'https://www.googleapis.com/calendar/v3/users/me/calendarList',
			qs: {
				minAccessRole: 'reader',
				access_token: token
			},
			strictSSL: true
		}, function(err, res, body) {
			if (err) return callback(false);

			if (res.statusCode !== 200) {
				return callback(false);
			}

			try {
				//Parse calendar list
				var doc = JSON.parse(body);
				callback(doc.items.length > 0);
			} catch (err) {
				callback(false);
			}
		});
	},
	intervals: [
		          5 * 60,            30, //5m after login, update every 30s
		     3 * 60 * 60,       10 * 60, //3h after login, update every 10m
		    24 * 60 * 60,       30 * 60, //1d after login, update every 30m
		7 * 24 * 60 * 60,   5 * 60 * 60 // 1w after login, update every 5h
	]
});<|endoftext|>


<commit_before>/**
 * Dependencies:
 * extend.js
 * point.js
 */

var _c = _c || {};

(function(_c) {
    "use strict";

    _c.draw = _c.draw || {};
    _c.draw.windowToCanvas = function(canvas, x, y) {
        var bbox = canvas.getBoundingClientRect();

        return new _c.draw.Point(x - bbox.left, y - bbox.top);
    }
})(_c);
<commit_msg>Optional point parameter for windowToCanvas()<commit_after>/**
 * Dependencies:
 * extend.js
 * point.js
 */

var _c = _c || {};

(function(_c) {
    "use strict";

    _c.draw = _c.draw || {};
    /**
     * Convert window coordinates to canvas coordinates. Providing
     * the optional point parameter improves performance if the
     * desired point already exists.
     * @param {Object} canvas - canvas relative to which coordinates
     * are to be determined
     * @param {Number} x - window x coordinate
     * @param {Number} y - window y coordinate
     * @param {Point} [point] - point in which to store result
     * @returns {Point}
     */
    _c.draw.windowToCanvas = function(canvas, x, y, point) {
        var bbox = canvas.getBoundingClientRect();

        if (point) {
            point.x = x - bbox.left;
            point.y = y - bbox.top;
            return point;
        }
        return new _c.draw.Point(x - bbox.left, y - bbox.top);
    }
})(_c);
<|endoftext|>


<commit_before>ENS.graphLabel = {};

// グラフラベルの横幅
ENS.graphLabel.LABEL_WIDTH = 200;
// カーソルとグラフラベルのトップオフセット
ENS.graphLabel.LABEL_TOP_OFFSET = 30;
// カーソルとグラフラベルのサイドオフセット
ENS.graphLabel.LABEL_LEFT_OFFSET = 10;
// 最大系列表示文字数
ENS.graphLabel.MAX_LABEL_LENGTH = 200;
// グラフのフルパスのタイトル
ENS.graphLabel.fullPathTitle = "";

// IDを指定してグラフラベルのDIV要素を作成する
ENS.graphLabel.create = function(id) {
	var $label = $("
");
	$label.attr("id", id);
	ENS.graphLabel._setAttr($label);
	return $label;
};

// 引数で与えたDIV要素をグラフラベル化する
ENS.graphLabel.modify = function($div) {
	ENS.graphLabel._setAttr($div);
};

ENS.graphLabel._setAttr = function($label) {
	$label.addClass("ensLabel");
	$label.css("width", ENS.graphLabel.LABEL_WIDTH + "px");
	$label.hide();
};

// マウスイベントのリスナを設定する
ENS.graphLabel.setEventListener = function($labelDiv, $graphDiv) {
	$graphDiv
			.mousemove(function(e) {
				var $contents = $("#contents_area");
				var cLeft = $contents.offset().left;
				var cTop = $contents.offset().top;
				var cWidth = $contents.width();
				var cHeight = $contents.height();
				var cScrollX = $contents.scrollLeft();
				var cScrollY = $contents.scrollTop();
				var graphPos = $(this).position();
				var labelPos = {};
				labelPos.top = e.pageY - cTop + ENS.graphLabel.LABEL_TOP_OFFSET
						+ cScrollY;
				labelPos.left = e.pageX - cLeft
						+ ENS.graphLabel.LABEL_LEFT_OFFSET + cScrollX;

				$labelDiv.show();

				// マップ画面の場合は位置を修正する
				if (graphPos.left === 0 && graphPos.top === 0) {
					labelPos.top = e.pageY - $(this).offset().top
							+ ENS.graphLabel.LABEL_TOP_OFFSET;
					labelPos.left = e.pageX - $(this).offset().left
							+ ENS.graphLabel.LABEL_LEFT_OFFSET;
				}

				// ラベルが画面右端に到達している場合、ラベルをカーソルの左側に移動させる
				if (cLeft + cWidth - ENS.graphLabel.LABEL_WIDTH < e.pageX) {
					labelPos.left = labelPos.left
							- (ENS.graphLabel.LABEL_LEFT_OFFSET * 2 + ENS.graphLabel.LABEL_WIDTH);
				}

				var labelHeight = $labelDiv.height();
				// ラベルが画面下端に到達している場合、ラベルをカーソルの左側に移動させる
				if (cTop + cHeight - labelHeight < e.pageY) {
					labelPos.top = labelPos.top
							- (ENS.graphLabel.LABEL_TOP_OFFSET * 3 + labelHeight);
				}

				// ラベルの位置を設定する
				$labelDiv.css("left", labelPos.left);
				$labelDiv.css("top", labelPos.top);

				// マウスカーソルがデータの存在しない場所にあるとき、
				// または固定値のデータ(1970/01/01 9:00)であるときは項目名をラベルに表示
				var labelDivHtml = $labelDiv.html();
				var compareLabelDivHtml = " " + labelDivHtml;
				var defaultDate = "1970/01/01 09:00";
				if (labelDivHtml.length <= 0
						|| compareLabelDivHtml.indexOf(" " + defaultDate) !== -1) {
					$labelDiv.html(ENS.graphLabel.fullPathTitle);
				}

				// 改行を追加する
				var text = $labelDiv.html();
				text = text.replace(//g, "
");
				$labelDiv.html(text);
			});
	$graphDiv.mouseout(function(e) {
		$labelDiv.hide();
	});
	$graphDiv.focusout(function(e) {
		$labelDiv.hide();
	});
};<commit_msg>Dashboardのグラフラベルの表示位置が、FireFoxでずれることがある問題を修正した。<commit_after>ENS.graphLabel = {};

// グラフラベルの横幅
ENS.graphLabel.LABEL_WIDTH = 200;
// カーソルとグラフラベルのトップオフセット
ENS.graphLabel.LABEL_TOP_OFFSET = 30;
// カーソルとグラフラベルのサイドオフセット
ENS.graphLabel.LABEL_LEFT_OFFSET = 10;
// 最大系列表示文字数
ENS.graphLabel.MAX_LABEL_LENGTH = 200;
// グラフのフルパスのタイトル
ENS.graphLabel.fullPathTitle = "";

// IDを指定してグラフラベルのDIV要素を作成する
ENS.graphLabel.create = function(id) {
	var $label = $("
");
	$label.attr("id", id);
	ENS.graphLabel._setAttr($label);
	return $label;
};

// 引数で与えたDIV要素をグラフラベル化する
ENS.graphLabel.modify = function($div) {
	ENS.graphLabel._setAttr($div);
};

ENS.graphLabel._setAttr = function($label) {
	$label.addClass("ensLabel");
	$label.css("width", ENS.graphLabel.LABEL_WIDTH + "px");
	$label.hide();
};

// マウスイベントのリスナを設定する
ENS.graphLabel.setEventListener = function($labelDiv, $graphDiv) {
	$graphDiv
			.mousemove(function(e) {
				var $contents = $("#contents_area");
				var cLeft = $contents.offset().left;
				var cTop = $contents.offset().top;
				var cWidth = $contents.width();
				var cHeight = $contents.height();
				var cScrollX = $contents.scrollLeft();
				var cScrollY = $contents.scrollTop();
				var graphPos = $(this).position();
				var labelPos = {};
				labelPos.top = e.pageY - cTop + ENS.graphLabel.LABEL_TOP_OFFSET
						+ cScrollY;
				labelPos.left = e.pageX - cLeft
						+ ENS.graphLabel.LABEL_LEFT_OFFSET + cScrollX;

				$labelDiv.show();

				// マップ画面の場合は位置を修正する
				if (graphPos.left < 1 && graphPos.top < 1) {
					labelPos.top = e.pageY - $(this).offset().top
							+ ENS.graphLabel.LABEL_TOP_OFFSET;
					labelPos.left = e.pageX - $(this).offset().left
							+ ENS.graphLabel.LABEL_LEFT_OFFSET;
				}

				// ラベルが画面右端に到達している場合、ラベルをカーソルの左側に移動させる
				if (cLeft + cWidth - ENS.graphLabel.LABEL_WIDTH < e.pageX) {
					labelPos.left = labelPos.left
							- (ENS.graphLabel.LABEL_LEFT_OFFSET * 2 + ENS.graphLabel.LABEL_WIDTH);
				}

				var labelHeight = $labelDiv.height();
				// ラベルが画面下端に到達している場合、ラベルをカーソルの左側に移動させる
				if (cTop + cHeight - labelHeight < e.pageY) {
					labelPos.top = labelPos.top
							- (ENS.graphLabel.LABEL_TOP_OFFSET * 3 + labelHeight);
				}

				// ラベルの位置を設定する
				$labelDiv.css("left", labelPos.left);
				$labelDiv.css("top", labelPos.top);

				// マウスカーソルがデータの存在しない場所にあるとき、
				// または固定値のデータ(1970/01/01 9:00)であるときは項目名をラベルに表示
				var labelDivHtml = $labelDiv.html();
				var compareLabelDivHtml = " " + labelDivHtml;
				var defaultDate = "1970/01/01 09:00";
				if (labelDivHtml.length <= 0
						|| compareLabelDivHtml.indexOf(" " + defaultDate) !== -1) {
					$labelDiv.html(ENS.graphLabel.fullPathTitle);
				}

				// 改行を追加する
				var text = $labelDiv.html();
				text = text.replace(//g, "
");
				$labelDiv.html(text);
			});
	$graphDiv.mouseout(function(e) {
		$labelDiv.hide();
	});
	$graphDiv.focusout(function(e) {
		$labelDiv.hide();
	});
};<|endoftext|>


<commit_before>(function() {
  var Time = {
    MINUTES_IN_HOUR        : 60,
    MILLISECONDS_IN_MINUTE : 60000,

    OFFSETS : [300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300, 240,
               300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300],
    UNTILS  : [1268550000000, 1289109600000, 1299999600000, 1320559200000,
               1331449200000, 1352008800000, 1362898800000, 1383458400000,
               1394348400000, 1414908000000, 1425798000000, 1446357600000,
               1457852400000, 1478412000000, 1489302000000, 1509861600000,
               1520751600000, 1541311200000, 1552201200000, 1572760800000,
               1583650800000, 1604210400000, null],

    formatDate: function(date) {
      return new Intl.DateTimeFormat(undefined, {
        month  : "long",
        day    : "numeric",
        weekday: "long"
      }).format(date);
    },

    formatTime: function(time) {
      return new Intl.DateTimeFormat(undefined, {
        hour   : "numeric",
        minute : "numeric"
      }).format(time);
    },

    offset: function() {
      var target  = Date.now(),
          untils  = this.UNTILS,
          offsets = this.OFFSETS,
          offset,
          offsetNext,
          offsetPrev;

      for (var index = 0; index < untils.length - 1; index++) {
        offset     = offsets[index];
        offsetNext = offsets[index + 1];
        offsetPrev = offsets[index ? index - 1 : index];

        if (offset < offsetNext && false) {
          offset = offsetNext;
        } else if (offset > offsetPrev && true) {
          offset = offsetPrev;
        }

        if (target < untils[index] - (offset * this.MILLISECONDS_IN_MINUTE)) {
          return offsets[index] / this.MINUTES_IN_HOUR;
        }
      }

      return offsets[untils.length - 1] / this.MINUTES_IN_HOUR;
    }
  };

  var now      = new Date(),
      hours    = now.getUTCHours(),
      slice    = Array.prototype.slice,
      offset   = Time.offset(),
      sections = slice.call(document.querySelectorAll("section"));

  if (navigator.platform.match(/Win/)) {
    document.querySelector("header h1 a").innerHTML = "Hockey";
  }

  if (hours < offset) {
    now.setUTCHours(hours - offset);
  }

  var year  = now.getUTCFullYear(),
      month = now.getUTCMonth() + 1,
      day   = now.getUTCDate(),
      limit = 7,
      count = 1;

  sections.forEach(function(section) {
    section.classList.remove("week");
  });

  sections
    .filter(function(section) {
      var parts        = section.querySelector("h1 time").getAttribute("datetime").split("-"),
          sectionYear  = parseInt(parts[0], 10),
          sectionMonth = parseInt(parts[1], 10),
          sectionDay   = parseInt(parts[2].split("T")[0], 10);

      return (sectionYear  > year) ||
             (sectionYear >= year && sectionMonth  > month) ||
             (sectionYear >= year && sectionMonth >= month && sectionDay >= day);
    })
    .forEach(function(section, index) {
      if (!section.querySelector("tr")) {
        return;
      } else if (count > limit && window.location.pathname === "/hockey/") {
        return;
      }

      count++;

      if (window.Intl && window.Intl.DateTimeFormat) {
        var time = section.querySelector("h1 time");

        time.innerText = Time.formatDate(
          new Date(time.getAttribute("datetime"))
        );

        slice.call(section.querySelectorAll("th time")).forEach(function(time) {
          var date = new Date(time.getAttribute("datetime"));

          time.textContent = date.getHours() === 3 ? "TBD" : Time.formatTime(date);
        });
      }

      section.classList.add("week");
    });

  window.addEventListener("load", function(e) {
    if (!window.applicationCache) {
      return;
    }

    window.applicationCache.addEventListener("updateready", function(e) {
      if (window.applicationCache.status !== window.applicationCache.UPDATEREADY) {
        return;
      }

      if (confirm("An updated schedule is available. Load it?")) {
        window.location.reload();
      }
    }, false);
  }, false);
})();
<commit_msg>Use "Today" as section header for the current day.<commit_after>(function() {
  var Time = {
    MINUTES_IN_HOUR        : 60,
    MILLISECONDS_IN_MINUTE : 60000,

    OFFSETS : [300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300, 240,
               300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300],
    UNTILS  : [1268550000000, 1289109600000, 1299999600000, 1320559200000,
               1331449200000, 1352008800000, 1362898800000, 1383458400000,
               1394348400000, 1414908000000, 1425798000000, 1446357600000,
               1457852400000, 1478412000000, 1489302000000, 1509861600000,
               1520751600000, 1541311200000, 1552201200000, 1572760800000,
               1583650800000, 1604210400000, null],

    formatDate: function(date) {
      return new Intl.DateTimeFormat(undefined, {
        month   : "long",
        day     : "numeric",
        weekday : "long"
      }).format(date);
    },

    formatTime: function(time) {
      return new Intl.DateTimeFormat(undefined, {
        hour   : "numeric",
        minute : "numeric"
      }).format(time);
    },

    offset: function() {
      var target  = Date.now(),
          untils  = this.UNTILS,
          offsets = this.OFFSETS,
          offset,
          offsetNext,
          offsetPrev;

      for (var index = 0; index < untils.length - 1; index++) {
        offset     = offsets[index];
        offsetNext = offsets[index + 1];
        offsetPrev = offsets[index ? index - 1 : index];

        if (offset < offsetNext && false) {
          offset = offsetNext;
        } else if (offset > offsetPrev && true) {
          offset = offsetPrev;
        }

        if (target < untils[index] - (offset * this.MILLISECONDS_IN_MINUTE)) {
          return offsets[index] / this.MINUTES_IN_HOUR;
        }
      }

      return offsets[untils.length - 1] / this.MINUTES_IN_HOUR;
    }
  };

  var now      = new Date(),
      hours    = now.getUTCHours(),
      slice    = Array.prototype.slice,
      offset   = Time.offset(),
      sections = slice.call(document.querySelectorAll("section"));

  if (navigator.platform.match(/Win/)) {
    document.querySelector("header h1 a").innerHTML = "Hockey";
  }

  if (hours < offset) {
    now.setUTCHours(hours - offset);
  }

  var year  = now.getUTCFullYear(),
      month = now.getUTCMonth() + 1,
      day   = now.getUTCDate(),
      limit = 7,
      count = 1;

  sections.forEach(function(section) {
    section.classList.remove("week");
  });

  sections
    .filter(function(section) {
      var parts        = section.querySelector("h1 time").getAttribute("datetime").split("-"),
          sectionYear  = parseInt(parts[0], 10),
          sectionMonth = parseInt(parts[1], 10),
          sectionDay   = parseInt(parts[2].split("T")[0], 10);

      return (sectionYear >  year) ||
             (sectionYear >= year && sectionMonth >  month) ||
             (sectionYear >= year && sectionMonth >= month && sectionDay >= day);
    })
    .forEach(function(section, index) {
      if (!section.querySelector("tr")) {
        return;
      } else if (count > limit && window.location.pathname === "/hockey/") {
        return;
      }

      count++;

      if (window.Intl && window.Intl.DateTimeFormat) {
        var time         = section.querySelector("h1 time");
            parts        = time.getAttribute("datetime").split("-"),
            sectionYear  = parseInt(parts[0], 10),
            sectionMonth = parseInt(parts[1], 10),
            sectionDay   = parseInt(parts[2].split("T")[0], 10);

        if (sectionYear === year && sectionMonth === month && sectionDay === day) {
          time.innerText = "Today";
        } else {
          time.innerText = Time.formatDate(
            new Date(time.getAttribute("datetime"))
          );
        }

        slice.call(section.querySelectorAll("th time")).forEach(function(time) {
          var date = new Date(time.getAttribute("datetime"));

          time.textContent = date.getHours() === 3 ? "TBD" : Time.formatTime(date);
        });
      }

      section.classList.add("week");
    });

  window.addEventListener("load", function(e) {
    if (!window.applicationCache) {
      return;
    }

    window.applicationCache.addEventListener("updateready", function(e) {
      if (window.applicationCache.status !== window.applicationCache.UPDATEREADY) {
        return;
      }

      if (confirm("An updated schedule is available. Load it?")) {
        window.location.reload();
      }
    }, false);
  }, false);
})();
<|endoftext|>


<commit_before>module.exports = function (grunt) {
	'use strict';

	var conf = {
		connect: {
			server: {
				options: {
					port: 8001,
					keepalive: true
				}
			}
		}
	};

	grunt.initConfig(conf);

	grunt.loadNpmTasks('grunt-contrib-connect');

	grunt.registerTask('default', ['connect']);
}
<commit_msg>WebRx: Remove gruntfile<commit_after><|endoftext|>


<commit_before>/*!
 * @package   ElkArte Forum
 * @copyright ElkArte Forum contributors
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
 *
 * @version 2.0 dev
 */

/**
 * This file contains javascript associated with the atwho function as it
 * relates to an sceditor invocation
 */
var disableDrafts = false;

(function (sceditor)
{
	'use strict';

	// Editor instance
	var editor,
		rangeHelper;

	function Elk_Mentions(options)
	{
		// All the passed options and defaults are loaded to the opts object
		this.opts = $.extend({}, this.defaults, options);
	}

	Elk_Mentions.prototype.attachAtWho = function (oMentions, $element, oIframeWindow)
	{
		var mentioned = $('#mentioned');

		// Create / use a container to hold the results
		if (mentioned.length === 0)
		{
			$('#' + oMentions.opts.editor_id).after(oMentions.opts._mentioned);
		}
		else
		{
			oMentions.opts._mentioned = mentioned;
		}

		oMentions.opts.cache.mentions = this.opts._mentioned;

		$element.atwho({
			at: "@",
			limit: 8,
			maxLen: 25,
			displayTpl: "
${name}
",
			acceptSpaceBar: true,
			callbacks: {
				filter: function (query, items, search_key)
				{
					// Already cached this query, then use it
					if (typeof oMentions.opts.cache.names[query] !== 'undefined')
					{
						return oMentions.opts.cache.names[query];
					}

					return [];
				},
				// Well then lets make a find member suggest call
				remoteFilter: function (query, callback)
				{
					// Let be easy-ish on the server, don't go looking until we have at least two characters
					if (query.length < 2)
					{
						return;
					}

					// No slamming the server either
					var current_call = parseInt(new Date().getTime() / 1000);
					if (oMentions.opts._last_call !== 0 && oMentions.opts._last_call + 0.5 > current_call)
					{
						callback(oMentions.opts._names);
						return;
					}

					// What we want
					var obj = {
						"suggest_type": "member",
						"search": query.php_urlencode(),
						"time": current_call
					};

					// Make the request
					suggest(obj, function ()
					{
						// Update the time gate
						oMentions.opts._last_call = current_call;

						// Update the cache with the values for reuse in local filter
						oMentions.opts.cache.names[query] = oMentions.opts._names;

						// Update the query cache for use in revalidateMentions
						oMentions.opts.cache.queries[oMentions.opts.cache.queries.length] = query;

						callback(oMentions.opts._names);
					});
				},
				beforeInsert: function (value, $li)
				{
					oMentions.addUID($li.data('id'), $li.data('value'));

					return value;
				},
				matcher: function (flag, subtext, should_startWithSpace, acceptSpaceBar)
				{
					var _a, _y, match, regexp, space;

					flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");

					if (should_startWithSpace)
					{
						flag = '(?:^|\\s)' + flag;
					}

					// Allow À - ÿ
					_a = decodeURI("%C3%80");
					_y = decodeURI("%C3%BF");

					// Allow first last name entry?
					space = acceptSpaceBar ? "\ " : "";

					// regexp = new RegExp(flag + '([^ <>&"\'=\\\\\n]*)$|' + flag + '([^\\x00-\\xff]*)$', 'gi');
					regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\\[\\]\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi');
					match = regexp.exec(subtext);

					if (match)
					{
						return match[2] || match[1];
					}
					else
					{
						return null;
					}
				},
				highlighter: function (li, query)
				{
					var regexp;

					if (!query)
					{
						return li;
					}

					// Preg Quote regexp from http://phpjs.org/functions/preg_quote/
					query = query.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'), '\\$&');

					regexp = new RegExp(">\\s*(\\w*)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig');
					return li.replace(regexp, function (str, $1, $2, $3)
					{
						return '> ' + $1 + '' + $2 + '' + $3 + ' <';
					});
				},
				beforeReposition: function (offset)
				{
					// We only need to adjust when in wysiwyg
					if (editor.inSourceMode())
					{
						return offset;
					}

					// Lets get the caret position so we can add the mentions box there
					var corrected_offset = findAtPosition();

					offset.top = corrected_offset.top;
					offset.left = corrected_offset.left;

					return offset;
				}
			}
		});

		// Use atwho selection box show/hide events to prevent autosave from firing
		$(oIframeWindow).on("shown.atwho", function (event, offset)
		{
			disableDrafts = true;
		});

		$(oIframeWindow).on("hidden.atwho", function (event, offset)
		{
			disableDrafts = false;
		});

		/**
		 * Makes the ajax call for data, returns to callback function when done.
		 *
		 * @param obj values to pass to action suggest
		 * @param callback function to call when we have completed our call
		 */
		function suggest(obj, callback)
		{
			var postString = "jsonString=" + JSON.stringify(obj) + "&" + elk_session_var + "=" + elk_session_id;

			oMentions.opts._names = [];

			$.ajax({
				url: elk_scripturl + "?action=suggest;xml",
				type: "post",
				data: postString,
				dataType: "xml"
			})
				.done(function (data)
				{
					$(data).find('item').each(function (idx, item)
					{
						oMentions.opts._names[idx] = {
							"id": $(item).attr('id'),
							"name": $(item).text()
						};
					});

					callback();
				})
				.fail(function (jqXHR, textStatus, errorThrown)
				{
					if ('console' in window)
					{
						window.console.info('Error:', textStatus, errorThrown.name);
						window.console.info(jqXHR.responseText);
					}

					callback();
				});
		}

		/**
		 * Determine the caret position inside of sceditor's iframe
		 *
		 * What it does:
		 * - Caret.js does not seem to return the correct position for (FF & IE) when
		 * the iframe has vertically scrolled.
		 * - This is an sceditor specific function to return a screen caret position
		 * - Called just before At.js adds the mentions dropdown box
		 * - Finds the @mentions tag and adds an invisible zero width space before it
		 * - Gets the location offset() in the iframe "window" of the added space
		 * - Adjusts for the iframe scroll
		 * - Adds in the iframe container location offset() to main window
		 * - Removes the space, restores the editor range.
		 *
		 * @returns {{}}
		 */
		function findAtPosition()
		{
			// Get sceditor's RangeHelper for use
			rangeHelper = editor.getRangeHelper();

			// Save the current state
			rangeHelper.saveRange();

			var start = rangeHelper.getMarker('sceditor-start-marker'),
				parent = start.parentNode,
				prev = start.previousSibling,
				offset = {},
				atPos,
				placefinder;

			// Create a placefinder span containing a 'ZERO WIDTH SPACE' Character
			placefinder = start.ownerDocument.createElement('span');
			$(placefinder).text("200B").addClass('placefinder');

			// Look back and find the mentions @ tag, so we can insert our span ahead of it
			while (prev)
			{
				atPos = (prev.nodeValue || '').lastIndexOf('@');

				// Found the start of @mention
				if (atPos > -1)
				{
					parent.insertBefore(placefinder, prev.splitText(atPos + 1));
					break;
				}

				prev = prev.previousSibling;
			}

			// If we were successful in adding the placefinder
			if (placefinder.parentNode)
			{
				var $_placefinder = $(placefinder);

				// offset() returns the top offset inside the total iframe, so we need the vertical scroll
				// value to adjust back to main window position
				//	wizzy_height = $('#' + oMentions.opts.editor_id).parent().find('iframe').height(),
				//	wizzy_window = $('#' + oMentions.opts.editor_id).parent().find('iframe').contents().height(),
				var wizzy_scroll = $('#' + oMentions.opts.editor_id).parent().find('iframe').contents().scrollTop();

				// Determine its Location in the iframe
				offset = $_placefinder.offset();

				// If we have scrolled, then we also need to account for those offsets
				offset.top -= wizzy_scroll;
				offset.top += $_placefinder.height();

				// Remove our placefinder
				$_placefinder.remove();
			}

			// Put things back just like we found them
			rangeHelper.restoreRange();

			// Add in the iframe's offset to get the final location.
			if (offset)
			{
				var iframeOffset = editor.getContentAreaContainer().offset();

				// Some fudge for the kids
				offset.top += iframeOffset.top + 5;
				offset.left += iframeOffset.left + 5;
			}

			return offset;
		}
	};

	Elk_Mentions.prototype.addUID = function (user_id, name)
	{
		this.opts._mentioned.append($('<input type="hidden" name="uid[]" />').val(user_id).attr('data-name', name));
	};

	/**
	 * Private mention vars
	 */
	Elk_Mentions.prototype.defaults = {
		_names: [],
		_last_call: 0,
		_mentioned: $('
')
	};

	/**
	 * Holds all current mention (defaults + passed options)
	 */
	Elk_Mentions.prototype.opts = {};

	/**
	 * Mentioning plugin interface to SCEditor
	 *  - Called from the editor as a plugin
	 *  - Monitors events so we control the elk_mention
	 */
	sceditor.plugins.mention = function ()
	{
		var base = this,
			oMentions;

		base.init = function ()
		{
			// Grab this instance for use use in oMentions
			editor = this;
		};

		/**
		 * Initialize, called when sceditor starts and initializes plugins
		 */
		base.signalReady = function ()
		{
			// Init the mention instance, load in the options
			oMentions = new Elk_Mentions(this.opts.mentionOptions);

			var $option_eid = $('#' + oMentions.opts.editor_id);

			// Adds the selector to the list of known "mentioner"
			add_elk_mention(oMentions.opts.editor_id, {isPlugin: true});
			oMentions.attachAtWho(oMentions, $option_eid.parent().find('textarea'));

			// Using wysiwyg, then lets attach atwho to it
			var instance = $option_eid.sceditor('instance');
			if (!instance.opts.runWithoutWysiwygSupport)
			{
				// We need to monitor the iframe window and body to text input
				var oIframe = $option_eid.parent().find('iframe')[0],
					oIframeWindow = oIframe.contentWindow,
					oIframeBody = $(oIframe.contentDocument.body);

				oMentions.attachAtWho(oMentions, oIframeBody, oIframeWindow);
			}
		};
	};
})(sceditor);
<commit_msg>! not really part of emoji, but updated to use the new extended function in sce that is part of this PR<commit_after>/*!
 * @package   ElkArte Forum
 * @copyright ElkArte Forum contributors
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
 *
 * @version 2.0 dev
 */

/**
 * This file contains javascript associated with the @mentions function as it
 * relates to an sceditor invocation
 */
var disableDrafts = false;

(function (sceditor)
{
	'use strict';

	// Editor instance
	var editor;

	function Elk_Mentions(options)
	{
		// All the passed options and defaults are loaded to the opts object
		this.opts = $.extend({}, this.defaults, options);
	}

	Elk_Mentions.prototype.attachAtWho = function (oMentions, $element, oIframeWindow)
	{
		let mentioned = $('#mentioned');

		// Create / use a container to hold the results
		if (mentioned.length === 0)
		{
			$('#' + oMentions.opts.editor_id).after(oMentions.opts._mentioned);
		}
		else
		{
			oMentions.opts._mentioned = mentioned;
		}

		oMentions.opts.cache.mentions = this.opts._mentioned;

		$element.atwho({
			at: "@",
			limit: 8,
			maxLen: 25,
			displayTpl: "
${name}
",
			acceptSpaceBar: true,
			callbacks: {
				filter: function (query, items, search_key)
				{
					// Already cached this query, then use it
					if (typeof oMentions.opts.cache.names[query] !== 'undefined')
					{
						return oMentions.opts.cache.names[query];
					}

					return [];
				},
				// Well then lets make a find member suggest call
				remoteFilter: function (query, callback)
				{
					// Let be easy-ish on the server, don't go looking until we have at least two characters
					if (query.length < 2)
					{
						return;
					}

					// No slamming the server either
					let current_call = Math.round(new Date().getTime() / 1000);
					if (oMentions.opts._last_call !== 0 && oMentions.opts._last_call + 0.5 > current_call)
					{
						callback(oMentions.opts._names);
						return;
					}

					// What we want
					var obj = {
						"suggest_type": "member",
						"search": query.php_urlencode(),
						"time": current_call
					};

					// Make the request
					suggest(obj, function ()
					{
						// Update the time gate
						oMentions.opts._last_call = current_call;

						// Update the cache with the values for reuse in local filter
						oMentions.opts.cache.names[query] = oMentions.opts._names;

						// Update the query cache for use in revalidateMentions
						oMentions.opts.cache.queries[oMentions.opts.cache.queries.length] = query;

						callback(oMentions.opts._names);
					});
				},
				beforeInsert: function (value, $li)
				{
					oMentions.addUID($li.data('id'), $li.data('value'));

					return value;
				},
				matcher: function (flag, subtext, should_startWithSpace, acceptSpaceBar)
				{
					let _a, _y, match, regexp, space;

					flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");

					if (should_startWithSpace)
					{
						flag = '(?:^|\\s)' + flag;
					}

					// Allow À - ÿ
					_a = decodeURI("%C3%80");
					_y = decodeURI("%C3%BF");

					// Allow first last name entry?
					space = acceptSpaceBar ? "\ " : "";

					// regexp = new RegExp(flag + '([^ <>&"\'=\\\\\n]*)$|' + flag + '([^\\x00-\\xff]*)$', 'gi');
					regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\\[\\]\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi');
					match = regexp.exec(subtext);

					if (match)
					{
						return match[2] || match[1];
					}
					else
					{
						return null;
					}
				},
				highlighter: function (li, query)
				{
					let regexp;

					if (!query)
					{
						return li;
					}

					// Preg Quote regexp from http://phpjs.org/functions/preg_quote/
					query = query.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'), '\\$&');

					regexp = new RegExp(">\\s*(\\w*)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig');
					return li.replace(regexp, function (str, $1, $2, $3)
					{
						return '> ' + $1 + '' + $2 + '' + $3 + ' <';
					});
				},
				beforeReposition: function (offset)
				{
					// We only need to adjust when in wysiwyg
					if (editor.inSourceMode())
					{
						return offset;
					}

					// Lets get the caret position so we can add the mentions box there
					let corrected_offset = editor.findCursorPosition('@');

					offset.top = corrected_offset.top;
					offset.left = corrected_offset.left;

					return offset;
				}
			}
		});

		// Use atwho selection box show/hide events to prevent autosave from firing
		if (Object.keys(oIframeWindow).length)
		{
			$(oIframeWindow).on("shown.atwho", function (event, offset)
			{
				disableDrafts = true;
			});

			$(oIframeWindow).on("hidden.atwho", function (event, offset)
			{
				disableDrafts = false;
			});
		}

		/**
		 * Makes the ajax call for data, returns to callback function when done.
		 *
		 * @param obj values to pass to action suggest
		 * @param callback function to call when we have completed our call
		 */
		function suggest(obj, callback)
		{
			let postString = "jsonString=" + JSON.stringify(obj) + "&" + elk_session_var + "=" + elk_session_id;

			oMentions.opts._names = [];

			$.ajax({
				url: elk_scripturl + "?action=suggest;xml",
				type: "post",
				data: postString,
				dataType: "xml"
			})
				.done(function (data)
				{
					$(data).find('item').each(function (idx, item)
					{
						oMentions.opts._names[idx] = {
							"id": $(item).attr('id'),
							"name": $(item).text()
						};
					});

					callback();
				})
				.fail(function (jqXHR, textStatus, errorThrown)
				{
					if ('console' in window)
					{
						window.console.info('Error:', textStatus, errorThrown.name);
						window.console.info(jqXHR.responseText);
					}

					callback();
				});
		}
	};

	Elk_Mentions.prototype.addUID = function (user_id, name)
	{
		this.opts._mentioned.append($('<input type="hidden" name="uid[]" />').val(user_id).attr('data-name', name));
	};

	/**
	 * Private mention vars
	 */
	Elk_Mentions.prototype.defaults = {
		_names: [],
		_last_call: 0,
		_mentioned: $('
')
	};

	/**
	 * Holds all current mention (defaults + passed options)
	 */
	Elk_Mentions.prototype.opts = {};

	/**
	 * Mentioning plugin interface to SCEditor
	 *  - Called from the editor as a plugin
	 *  - Monitors events so we control the elk_mention
	 */
	sceditor.plugins.mention = function ()
	{
		var base = this,
			oMentions;

		base.init = function ()
		{
			// Grab this instance for use use in oMentions
			editor = this;
		};

		/**
		 * Initialize, called when sceditor starts and initializes plugins
		 */
		base.signalReady = function ()
		{
			// Init the mention instance, load in the options
			oMentions = new Elk_Mentions(this.opts.mentionOptions);

			let original_textarea = document.getElementById(oMentions.opts.editor_id),
				instance = sceditor.instance(original_textarea),
				sceditor_textarea = instance.getContentAreaContainer().nextSibling;

			// Adds the selector to the list of known "mentioner"
			add_elk_mention(oMentions.opts.editor_id, {isPlugin: true});
			oMentions.attachAtWho(oMentions, $(sceditor_textarea), {});

			// Using wysiwyg, then lets attach atwho to it
			if (!instance.opts.runWithoutWysiwygSupport)
			{
				// We need to monitor the iframe window and body to text input
				let oIframe = instance.getContentAreaContainer(),
					oIframeWindow = oIframe.contentWindow,
					oIframeBody = oIframe.contentDocument.body;

				oMentions.attachAtWho(oMentions, $(oIframeBody), oIframeWindow);
			}
		};
	};
})(sceditor);
<|endoftext|>


<commit_before>const os = require('opensubtitles-api');
const axios = require('axios');
const srtToVtt = require('srt-to-vtt');
const config = require('../config');
const firebase = require('firebase-admin');

const osClient = new os({
    useragent: config.OS_USER_AGENT,
    ssl: true,
});
class OpenSubsClient {
    constructor() {
        this.bucket = firebase.storage().bucket();
        this.firestore = firebase.firestore();
    }
    getSubsLink(id, params) {
        console.log("Searching subs");
        return this.firestore.doc(`/subs/${params.imdbid}`)
            .get()
            .then(snapshot => {
                if (snapshot.exists) {
                    return this.firestore.doc(`/session/${id}`)
                        .update({subs: snapshot.doc()});
                }
                return osClient.search(params)
                .then(subtitles => {
                    const downloadProcess = Object.keys(subtitles)
                        .map(lang => {
                            return this.downloadSubtitle(subtitles[lang].url)
                                .then(stream => {
                                    return new Promise((resolve, reject) => {
                                        const subtitleFile = this.bucket.file(`subtitles/${params.imdbid}/${lang}/${subtitles[lang].filename.replace('.srt', '.vtt')}`);
                                        stream
                                        .pipe(srtToVtt())
                                        .pipe(subtitleFile.createWriteStream())
                                            .on('error', err => console.log(err))
                                            .on('finish', () => {
                                                console.log(subtitles[lang]);
                                                const expiredDate = new Date();
                                                expiredDate.setMonth(expiredDate.getMonth() + 1);
                                                subtitleFile.getSignedUrl({
                                                    action: 'read',
                                                    expires: expiredDate.toString(),
                                                }, (err, url) => {
                                                    if (err) {
                                                        console.log(err);
                                                        return resolve({
                                                            lang: subtitles[lang].code,
                                                            langName: subtitles[lang].lang,
                                                            url: ''
                                                        });
                                                    } else {
                                                        return resolve({
                                                            lang: subtitles[lang].code,
                                                            langName: subtitles[lang].lang,
                                                            url
                                                        });
                                                    }
                                                });
                                            })
                                    });
                                });
                        });
                        return Promise.all(downloadProcess)
                            .then(result => {
                                console.log(result);
                                this.firestore.doc(`/subs/${params.imdbid}`)
                                    .update({subs: result});
                                this.firestore.doc(`/session/${id}`)
                                .update({subs: result})
                                .then(() => {
                                    console.log(`All supported subs ready`);
                                    return Promise.resolve();
                                })
                                .catch(err => {
                                    console.log(err);
                                    return Promise.resolve();
                                });
                            })
                            .catch(err => {
                                console.log(err);
                                return Promise.resolve();
                            });
                });
            });
    }

    downloadSubtitle(url) {
        console.log(`Downloading ${url}`);
        return axios.get(url,
            {
                responseType: 'stream',
            })
            .then(resp => resp.data);
    }

}

module.exports = OpenSubsClient;<commit_msg>langcode<commit_after>const os = require('opensubtitles-api');
const axios = require('axios');
const srtToVtt = require('srt-to-vtt');
const config = require('../config');
const firebase = require('firebase-admin');

const osClient = new os({
    useragent: config.OS_USER_AGENT,
    ssl: true,
});
class OpenSubsClient {
    constructor() {
        this.bucket = firebase.storage().bucket();
        this.firestore = firebase.firestore();
    }
    getSubsLink(id, params) {
        console.log("Searching subs");
        return this.firestore.doc(`/subs/${params.imdbid}`)
            .get()
            .then(snapshot => {
                if (snapshot.exists) {
                    return this.firestore.doc(`/session/${id}`)
                        .update({subs: snapshot.doc()});
                }
                return osClient.search(params)
                .then(subtitles => {
                    const downloadProcess = Object.keys(subtitles)
                        .map(lang => {
                            return this.downloadSubtitle(subtitles[lang].url)
                                .then(stream => {
                                    return new Promise((resolve, reject) => {
                                        const subtitleFile = this.bucket.file(`subtitles/${params.imdbid}/${lang}/${subtitles[lang].filename.replace('.srt', '.vtt')}`);
                                        stream
                                        .pipe(srtToVtt())
                                        .pipe(subtitleFile.createWriteStream())
                                            .on('error', err => console.log(err))
                                            .on('finish', () => {
                                                console.log(subtitles[lang]);
                                                const expiredDate = new Date();
                                                expiredDate.setMonth(expiredDate.getMonth() + 1);
                                                subtitleFile.getSignedUrl({
                                                    action: 'read',
                                                    expires: expiredDate.toString(),
                                                }, (err, url) => {
                                                    if (err) {
                                                        console.log(err);
                                                        return resolve({
                                                            lang: subtitles[lang].langcode,
                                                            langName: subtitles[lang].lang,
                                                            url: ''
                                                        });
                                                    } else {
                                                        return resolve({
                                                            lang: subtitles[lang].langcode,
                                                            langName: subtitles[lang].lang,
                                                            url
                                                        });
                                                    }
                                                });
                                            })
                                    });
                                });
                        });
                        return Promise.all(downloadProcess)
                            .then(result => {
                                console.log(result);
                                this.firestore.doc(`/subs/${params.imdbid}`)
                                    .update({subs: result});
                                this.firestore.doc(`/session/${id}`)
                                .update({subs: result})
                                .then(() => {
                                    console.log(`All supported subs ready`);
                                    return Promise.resolve();
                                })
                                .catch(err => {
                                    console.log(err);
                                    return Promise.resolve();
                                });
                            })
                            .catch(err => {
                                console.log(err);
                                return Promise.resolve();
                            });
                });
            });
    }

    downloadSubtitle(url) {
        console.log(`Downloading ${url}`);
        return axios.get(url,
            {
                responseType: 'stream',
            })
            .then(resp => resp.data);
    }

}

module.exports = OpenSubsClient;<|endoftext|>


<commit_before>(function ($) {
  $.extend($.summernote.lang, {
    'ja-JP': {
      font: {
        bold: '太字',
        italic: '斜体',
        underline: '下線',
        clear: 'クリア',
        height: '文字高',
        name: 'フォント',
        strikethrough: '取り消し線',
        size: '大きさ'
      },
      image: {
        image: '画像',
        insert: '画像挿入',
        resizeFull: '最大化',
        resizeHalf: '1/2',
        resizeQuarter: '1/4',
        floatLeft: '左寄せ',
        floatRight: '右寄せ',
        floatNone: '寄せ解除',
        dragImageHere: 'ここに画像をドラッグしてください',
        selectFromFiles: '画像ファイルを選ぶ',
        url: 'URLから画像を挿入する',
        remove: '画像を削除する'
      },
      video: {
        video: '動画',
        videoLink: '動画リンク',
        insert: '動画挿入',
        url: '動画のURL',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, Youku)'
      },
      link: {
        link: 'リンク',
        insert: 'リンク挿入',
        unlink: 'リンク解除',
        edit: '編集',
        textToDisplay: 'リンク文字列',
        url: 'URLを入力してください',
        openInNewWindow: '新しいウィンドウで開く'
      },
      table: {
        table: 'テーブル'
      },
      hr: {
        insert: '水平線の挿入'
      },
      style: {
        style: 'スタイル',
        p: '標準',
        blockquote: '引用',
        pre: 'コード',
        h1: '見出し1',
        h2: '見出し2',
        h3: '見出し3',
        h4: '見出し4',
        h5: '見出し5',
        h6: '見出し6'
      },
      lists: {
        unordered: '通常リスト',
        ordered: '番号リスト'
      },
      options: {
        help: 'ヘルプ',
        fullscreen: 'フルスクリーン',
        codeview: 'コード表示'
      },
      paragraph: {
        paragraph: '文章',
        outdent: '字上げ',
        indent: '字下げ',
        left: '左寄せ',
        center: '中央寄せ',
        right: '右寄せ',
        justify: '均等割付'
      },
      color: {
        recent: '現在の色',
        more: 'もっと見る',
        background: '背景色',
        foreground: '文字色',
        transparent: '透過率',
        setTransparent: '透過率を設定',
        reset: '標準',
        resetToDefault: '標準に戻す'
      },
      shortcut: {
        shortcuts: 'ショートカット',
        close: '閉じる',
        textFormatting: '文字フォーマット',
        action: 'アクション',
        paragraphFormatting: '文章フォーマット',
        documentStyle: 'ドキュメント形式'
      },
      history: {
        undo: '元に戻す',
        redo: 'やり直す'
      }
    }
  });
})(jQuery);
<commit_msg>Update summernote-ja-JP.js<commit_after>(function ($) {
  $.extend($.summernote.lang, {
    'ja-JP': {
      font: {
        bold: '太字',
        italic: '斜体',
        underline: '下線',
        clear: 'クリア',
        height: '文字高',
        name: 'フォント',
        strikethrough: '取り消し線',
        size: '大きさ'
      },
      image: {
        image: '画像',
        insert: '画像挿入',
        resizeFull: '最大化',
        resizeHalf: '1/2',
        resizeQuarter: '1/4',
        floatLeft: '左寄せ',
        floatRight: '右寄せ',
        floatNone: '寄せ解除',
        dragImageHere: 'ここに画像をドラッグしてください',
        selectFromFiles: '画像ファイルを選ぶ',
        url: 'URLから画像を挿入する',
        remove: '画像を削除する'
      },
      video: {
        video: '動画',
        videoLink: '動画リンク',
        insert: '動画挿入',
        url: '動画のURL',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, Youku)'
      },
      link: {
        link: 'リンク',
        insert: 'リンク挿入',
        unlink: 'リンク解除',
        edit: '編集',
        textToDisplay: 'リンク文字列',
        url: 'URLを入力してください',
        openInNewWindow: '新しいウィンドウで開く'
      },
      table: {
        table: 'テーブル'
      },
      hr: {
        insert: '水平線の挿入'
      },
      style: {
        style: 'スタイル',
        p: '標準',
        blockquote: '引用',
        pre: 'コード',
        h1: '見出し1',
        h2: '見出し2',
        h3: '見出し3',
        h4: '見出し4',
        h5: '見出し5',
        h6: '見出し6'
      },
      lists: {
        unordered: '通常リスト',
        ordered: '番号リスト'
      },
      options: {
        help: 'ヘルプ',
        fullscreen: 'フルスクリーン',
        codeview: 'コード表示'
      },
      paragraph: {
        paragraph: '文章',
        outdent: '字上げ',
        indent: '字下げ',
        left: '左寄せ',
        center: '中央寄せ',
        right: '右寄せ',
        justify: '均等割付'
      },
      color: {
        recent: '現在の色',
        more: 'もっと見る',
        background: '背景色',
        foreground: '文字色',
        transparent: '透過率',
        setTransparent: '透過率を設定',
        reset: '標準',
        resetToDefault: '標準に戻す'
      },
      shortcut: {
        shortcuts: 'ショートカット',
        close: '閉じる',
        textFormatting: '文字フォーマット',
        action: 'アクション',
        paragraphFormatting: '文章フォーマット',
        documentStyle: 'ドキュメント形式'
      },
      history: {
        undo: '元に戻す',
        redo: 'やり直す'
      },
      help: {
        insertParagraph: '改行挿入',
        undo: '一旦、行った操作を戻す',
        redo: '最後のコマンドをやり直す',
        tab: 'Tab',
        untab: 'タブ戻し',
        bold: '太文字',
        italic: '斜体',
        underline: '下線',
        strikethrough: '取り消し線',
        removeFormat: '装飾を戻す',
        justifyLeft: '左寄せ',
        justifyCenter: '真ん中寄せ',
        justifyRight: '右寄せ',
        justifyFull: 'すべてを整列',
        insertUnorderedList: '行頭に●を挿入',
        insertOrderedList: '行頭に番号を挿入',
        outdent: '字下げを戻す（アウトデント）',
        indent: '字下げする（インデント）',
        formatPara: '段落(P tag)指定',
        formatH1: 'H1指定',
        formatH2: 'H2指定',
        formatH3: 'H3指定',
        formatH4: 'H4指定',
        formatH5: 'H5指定',
        formatH6: 'H6指定',
        insertHorizontalRule: '<hr />を挿入',
        linkDialog.show: 'リンク挿入'
      }
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>import gulp from "gulp";
import plumber from "gulp-plumber";
import pug from "gulp-pug";
import posthtml from "gulp-posthtml";
import prettify from "gulp-prettify";
import gulpIf from "gulp-if";
import { setup as emittySetup } from "emitty";

import getJsonData from "../util/getJsonData";
import { plumberConfig, posthtmlConfig, htmlPrettifyConfig } from "../config";
import data from "./data";

export const pages = () => {
  const pugConfig = {
    locals: getJsonData("./tmp/data.json")
  };

  const emittyPug = emittySetup("source/pages", "pug");

  return new Promise((resolve, reject) => {
    return emittyPug
      .scan(global.emittyChangedFile)
      .then(() => {
        gulp
          .src(["**/*.pug", "!**/_*.pug"], { cwd: "source/pages" })
          .pipe(plumber(plumberConfig))
          .pipe(
            gulpIf(global.watch, emittyPug.filter(global.emittyChangedFile))
          )
          .pipe(pug(pugConfig))
          .pipe(posthtml(posthtmlConfig.plugins, posthtmlConfig.options))
          .pipe(prettify(htmlPrettifyConfig))
          .pipe(gulp.dest("dest"))
          .on("end", resolve)
          .on("error", reject);
      })
      .catch(err => console.log(err));
  });
};

export const html = gulp.series(data, pages);
<commit_msg>Remove emitty<commit_after>import gulp from "gulp";
import plumber from "gulp-plumber";
import pug from "gulp-pug";
import posthtml from "gulp-posthtml";
import prettify from "gulp-prettify";

import getJsonData from "../util/getJsonData";
import { plumberConfig, posthtmlConfig, htmlPrettifyConfig } from "../config";
import data from "./data";

export function pages() {
  const pugConfig = {
    locals: getJsonData("./tmp/data.json")
  };

  return gulp
    .src(["**/*.pug", "!**/_*.pug"], { cwd: "source/pages" })
    .pipe(plumber(plumberConfig))
    .pipe(pug(pugConfig))
    .pipe(posthtml(posthtmlConfig.plugins, posthtmlConfig.options))
    .pipe(prettify(htmlPrettifyConfig))
    .pipe(gulp.dest("dest"));
}

export const html = gulp.series(data, pages);
<|endoftext|>


<commit_before>/* jshint browser: true */
/* jshint unused: false */
/* global _, frontendConfig, arangoHelper, Backbone, window, templateEngine, $ */

(function () {
  'use strict';

  window.UserPermissionView = Backbone.View.extend({
    el: '#content',

    template: templateEngine.createTemplate('userPermissionView.ejs'),

    initialize: function (options) {
      this.username = options.username;
    },

    events: {
      'click #userPermissionView [type="checkbox"]': 'setPermission'
    },

    render: function () {
      var self = this;

      this.collection.fetch({
        success: function () {
          self.continueRender();
        }
      });
    },

    setPermission: function (e) {
      var checked = $(e.currentTarget).is(':checked');
      var db = $(e.currentTarget).attr('name');

      if (checked) {
        this.grantPermission(this.currentUser.get('user'), db);
      } else {
        this.revokePermission(this.currentUser.get('user'), db);
      }
    },

    grantPermission: function (user, db) {
      $.ajax({
        type: 'PUT',
        url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(user) + '/database/' + encodeURIComponent(db)),
        contentType: 'application/json',
        data: JSON.stringify({
          grant: 'rw'
        })
      });
    },

    revokePermission: function (user, db) {
      $.ajax({
        type: 'PUT',
        url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(user) + '/database/' + encodeURIComponent(db)),
        contentType: 'application/json'
      });
    },

    continueRender: function () {
      var self = this;

      this.currentUser = this.collection.findWhere({
        user: this.username
      });

      this.breadcrumb();

      arangoHelper.buildUserSubNav(this.currentUser.get('user'), 'Permissions');

      var url = arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(self.currentUser.get('user')) + '/database');
      if (frontendConfig.db === '_system') {
        url = arangoHelper.databaseUrl('/_api/user/root/database');
      }

      // FETCH COMPLETE DB LIST
      $.ajax({
        type: 'GET',
        url: url,
        contentType: 'application/json',
        success: function (data) {
          var allDBs = data.result;

          // NOW FETCH USER PERMISSIONS
          $.ajax({
            type: 'GET',
            url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(self.currentUser.get('user')) + '/database'),
            // url: arangoHelper.databaseUrl("/_api/database/user/" + encodeURIComponent(this.currentUser.get("user"))),
            contentType: 'application/json',
            success: function (data) {
              var permissions = data.result;
              if (allDBs._system) {
                var arr = [];
                _.each(allDBs, function (db, name) {
                  arr.push(name);
                });
                allDBs = arr;
              }
              self.finishRender(allDBs, permissions);
            }
          });
        }
      });
    },

    finishRender: function (allDBs, permissions) {
      _.each(permissions, function (value, key) {
        if (value !== 'rw') {
          delete permissions[key];
        }
      });

      $(this.el).html(this.template.render({
        allDBs: allDBs,
        permissions: permissions
      }));
    },

    breadcrumb: function () {
      $('#subNavigationBar .breadcrumb').html(
        'User: ' + this.currentUser.get('user')
      );
    }

  });
}());
<commit_msg>issue: #2181<commit_after>/* jshint browser: true */
/* jshint unused: false */
/* global _, frontendConfig, arangoHelper, Backbone, window, templateEngine, $ */

(function () {
  'use strict';

  window.UserPermissionView = Backbone.View.extend({
    el: '#content',

    template: templateEngine.createTemplate('userPermissionView.ejs'),

    initialize: function (options) {
      this.username = options.username;
    },

    events: {
      'click #userPermissionView [type="checkbox"]': 'setPermission'
    },

    render: function () {
      var self = this;

      this.collection.fetch({
        success: function () {
          self.continueRender();
        }
      });
    },

    setPermission: function (e) {
      var checked = $(e.currentTarget).is(':checked');
      var db = $(e.currentTarget).attr('name');

      if (checked) {
        this.grantPermission(this.currentUser.get('user'), db);
      } else {
        if (db === '_system') {
          // special case, ask if user really want to revoke persmission here
          var buttons = []; var tableContent = [];

          tableContent.push(
            window.modalView.createReadOnlyEntry(
              'db-system-revoke-button',
              'Caution',
              'You are removing your permissions to _system database. Really continue?',
              undefined,
              undefined,
              false
            )
          );
          buttons.push(
            window.modalView.createSuccessButton('Revoke', this.revokePermission.bind(this, this.currentUser.get('user'), db))
          );
          buttons.push(
            window.modalView.createCloseButton('Cancel', this.rollbackInputButton.bind(this, db))
          );
          window.modalView.show('modalTable.ejs', 'Revoke _system Database Permission', buttons, tableContent);
        } else {
          this.revokePermission(this.currentUser.get('user'), db);
        }
      }
    },

    rollbackInputButton: function (name) {
      $('input[name="' + name + '"').prop('checked', 'true');
    },

    grantPermission: function (user, db) {
      $.ajax({
        type: 'PUT',
        url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(user) + '/database/' + encodeURIComponent(db)),
        contentType: 'application/json',
        data: JSON.stringify({
          grant: 'rw'
        })
      });
    },

    revokePermission: function (user, db) {
      $.ajax({
        type: 'PUT',
        url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(user) + '/database/' + encodeURIComponent(db)),
        contentType: 'application/json'
      });
      window.modalView.hide();
    },

    continueRender: function () {
      var self = this;

      this.currentUser = this.collection.findWhere({
        user: this.username
      });

      this.breadcrumb();

      arangoHelper.buildUserSubNav(this.currentUser.get('user'), 'Permissions');

      var url = arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(self.currentUser.get('user')) + '/database');
      if (frontendConfig.db === '_system') {
        url = arangoHelper.databaseUrl('/_api/user/root/database');
      }

      // FETCH COMPLETE DB LIST
      $.ajax({
        type: 'GET',
        url: url,
        contentType: 'application/json',
        success: function (data) {
          var allDBs = data.result;

          // NOW FETCH USER PERMISSIONS
          $.ajax({
            type: 'GET',
            url: arangoHelper.databaseUrl('/_api/user/' + encodeURIComponent(self.currentUser.get('user')) + '/database'),
            // url: arangoHelper.databaseUrl("/_api/database/user/" + encodeURIComponent(this.currentUser.get("user"))),
            contentType: 'application/json',
            success: function (data) {
              var permissions = data.result;
              if (allDBs._system) {
                var arr = [];
                _.each(allDBs, function (db, name) {
                  arr.push(name);
                });
                allDBs = arr;
              }
              self.finishRender(allDBs, permissions);
            }
          });
        }
      });
    },

    finishRender: function (allDBs, permissions) {
      _.each(permissions, function (value, key) {
        if (value !== 'rw') {
          delete permissions[key];
        }
      });

      $(this.el).html(this.template.render({
        allDBs: allDBs,
        permissions: permissions
      }));
    },

    breadcrumb: function () {
      $('#subNavigationBar .breadcrumb').html(
        'User: ' + this.currentUser.get('user')
      );
    }

  });
}());
<|endoftext|>