<commit_before>"use strict";

var socketIO = require('socket.io'),
    connect = require("connect"),
    cookie = require("cookie"),
    Session = require('connect').middleware.session.Session;

var utils = connect.utils,
    session = require("../../session.js"),
    config = require("../../../shared/config"),
    log = require("../../../shared/logger.js").get("server"),
    websocketAdapter = require("./websocketAdapter.js");

function init(io) {

    io.set('authorization', function (data, accept) {

        if(config.useSession === true) {

            if (!data.headers.cookie) {
                log.debug("websocket connection attempt without cookie!");
                //maybe start a session for this websocket here.
                return accept('No cookie transmitted.', false);
            }

            var cookies = data.headers.cookie,
                sess = session.get();

            //we need the session-config in order to get the data from connect
            var secret = sess.secret,
                store = sess.store,
                sessionKey = sess.key;

            if (cookies) {
                try {
                    data.cookies = cookie.parse(cookies);
                    if (secret) {
                        data.signedCookies = utils.parseSignedCookies(data.cookies, secret);
                        var obj = utils.parseJSONCookies(data.signedCookies);
                        //load the session before it's overwritten below
                        data.sessionID = data.signedCookies[sessionKey];
                        data.signedCookies = obj;
                    }
                    data.cookies = utils.parseJSONCookies(data.cookies);
                } catch (err) {
                    console.log("err", err);
                }
            }

            //further investigation needed here
            //https://github.com/senchalabs/connect/blob/master/lib/middleware/session/store.js
            //http://www.danielbaulig.de/socket-ioexpress/#comment-2705
            store.load(data.sessionID, function (err, session) {

                if (err) {
                    // if we cannot grab a session, turn down the connection
                    accept(err.message, false);
                } else {

                    if(!session) {
                        accept("Session not set", false);
                        return;
                    }

                    data.session = session;

                    accept(null, true);
                }
            });
        }
        else {
            //we accept and don't check for cookies on disabled session support
            data.session = null;
            return accept(null, true);
        }
    });

    function refreshSessionData(socket, callback) {

        //only refresh if session is defined
        if(socket.handshake.session) {
            socket.handshake.session.reload( function (err) {

                if(err) {
                    throw new Error(err);
                }

                // "touch" it (resetting maxAge and lastAccess)
                socket.handshake.session = socket.handshake.session.req.session;
                socket.handshake.session.touch();

                callback(socket.handshake.session);
            });
        }else {
            callback(null);
        }

    }

    io.sockets.on('connection', function (socket) {

        socket.on("create", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "create", sessionData, url, data, cb);
            });
        });

        socket.on("read", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "read", sessionData, url, data, cb);
            });
        });

        socket.on("update", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "update", sessionData, url, data, cb);
            });
        });

        socket.on("destroy", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "destroy", sessionData, url, data, cb);
            });
        });
    });
}

exports.init = init;<commit_msg>- update for config.use.session<commit_after>"use strict";

var socketIO = require('socket.io'),
    connect = require("connect"),
    cookie = require("cookie"),
    Session = require('connect').middleware.session.Session;

var utils = connect.utils,
    session = require("../../session.js"),
    config = require("../../../shared/config"),
    log = require("../../../shared/logger.js").get("server"),
    websocketAdapter = require("./websocketAdapter.js");

function init(io) {

    io.set('authorization', function (data, accept) {

        if(config.use.session === true) {

            if (!data.headers.cookie) {
                log.debug("websocket connection attempt without cookie!");
                //maybe start a session for this websocket here.
                return accept('No cookie transmitted.', false);
            }

            var cookies = data.headers.cookie,
                sess = session.get();

            //we need the session-config in order to get the data from connect
            var secret = sess.secret,
                store = sess.store,
                sessionKey = sess.key;

            if (cookies) {
                try {
                    data.cookies = cookie.parse(cookies);
                    if (secret) {
                        data.signedCookies = utils.parseSignedCookies(data.cookies, secret);
                        var obj = utils.parseJSONCookies(data.signedCookies);
                        //load the session before it's overwritten below
                        data.sessionID = data.signedCookies[sessionKey];
                        data.signedCookies = obj;
                    }
                    data.cookies = utils.parseJSONCookies(data.cookies);
                } catch (err) {
                    console.log("err", err);
                }
            }

            //further investigation needed here
            //https://github.com/senchalabs/connect/blob/master/lib/middleware/session/store.js
            //http://www.danielbaulig.de/socket-ioexpress/#comment-2705
            store.load(data.sessionID, function (err, session) {

                if (err) {
                    // if we cannot grab a session, turn down the connection
                    accept(err.message, false);
                } else {

                    if(!session) {
                        accept("Session not set", false);
                        return;
                    }

                    data.session = session;

                    accept(null, true);
                }
            });
        }
        else {
            //we accept and don't check for cookies on disabled session support
            data.session = null;
            return accept(null, true);
        }
    });

    function refreshSessionData(socket, callback) {

        //only refresh if session is defined
        if(socket.handshake.session) {
            socket.handshake.session.reload( function (err) {

                if(err) {
                    throw new Error(err);
                }

                // "touch" it (resetting maxAge and lastAccess)
                socket.handshake.session = socket.handshake.session.req.session;
                socket.handshake.session.touch();

                callback(socket.handshake.session);
            });
        }else {
            callback(null);
        }

    }

    io.sockets.on('connection', function (socket) {

        socket.on("create", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "create", sessionData, url, data, cb);
            });
        });

        socket.on("read", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "read", sessionData, url, data, cb);
            });
        });

        socket.on("update", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "update", sessionData, url, data, cb);
            });
        });

        socket.on("destroy", function(url, data, cb){
            refreshSessionData(socket, function onSessionDataRefreshed(sessionData) {
                websocketAdapter(socket, "destroy", sessionData, url, data, cb);
            });
        });
    });
}

exports.init = init;<|endoftext|>


<commit_before>import React from 'react'
import Link from 'gatsby-link'
import Vivus from 'vivus'
import Tagline from '../components/Tagline'
import Header from '../components/Header'
import HeroText from '../components/HeroText'
import Container from '../components/utils/Container'
import Row from '../components/utils/Row'
import Col12 from '../components/utils/Col12'
import ColSM4 from '../components/utils/ColSM4'
import reactlogo from '../img/react-logo.svg'
import nodelogo from '../img/nodejs-logo.svg'
import wordpresslogo from '../img/wordpress-logo.svg'
import phplogo from '../img/php-logo.svg'
import shopifylogo from '../img/shopify-logo.svg'
import ioslogo from '../img/ios-logo.svg'
import androidlogo from '../img/android-logo.svg'

// TODO: put partial sections into react js components and add portfolio section

const IndexPage = () =>

      <Container>
        <Row>
          <Col12>

Hi, welcome to several levels. My name is Harrison McGuire and I am the founder and lead software developer. I'm dedicated to making excellent, performant, modern websites.

          </Col12>
        </Row>

The Modern Web is Built with JavaScript

JavaScript has quickly taking over the web community with its versatility and vast range of powers

this site is made with React and Gatsby JS

        <Row>
          <ColSM4>
            <svg xmlns="http://www.w3.org/2000/svg" className="svg-logo mx-auto" viewBox="0 0 630 630">
              <rect width="630" height="630" fill="#f7df1e"/>
              <path d="m423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z"/>
            </svg>

JavaScript

The high-level programming language is extremely dynamic and powerful and I can make some magnificent software with JavaScript.

          </ColSM4>
          <ColSM4>

React

React is my preferred Javascript library. React’s flexibility and the component based structure makes it easy to work with while making extremely powerful apps.

          </ColSM4>
          <ColSM4>

NodeJS

NodeJS keeps my workflow in JavaScript and allows for apps to be built quickly and efficiently. Node is async by nature thus keeping sites running at optimal performance.

          </ColSM4>
        </Row>
      </Container>

      <HeroText>
        <Container>

several levels

web and app development

"I do things different striving for originality and modernity"

        </Container>
      </HeroText>

      <Container>

To Live and Breath With a CMS

CMS's can make the backend user experience incredible, but they can also add a lot of weight and unnecessary code to the project. I customize CMS themes to ensure great performance and user accessibility

        <Row>
          <ColSM4>

WordPress

I make custom themes and plugins for the world's most popular CMS.

          </ColSM4>
          <ColSM4>

PHP

PHP is the backbone of most of the world's servers that powers a majority of websites. PHP is necessary for all WordPress configurations.

          </ColSM4>
          <ColSM4>

Shopify

Shopify is my preferred ecommerce platform. I customize themes and generate dynamic front facing stores.

          </ColSM4>
        </Row>
      </Container>

      <HeroText>
        <Container>

"having the world's information in your pocket takes unrelenting responsibility"

        </Container>
      </HeroText>

      <Container>

The World in Our Pocket

app development can directly bring prodcuts to a user's hands

        <Row>
          <ColSM4>

iOS

I develop iOS apps with Swift. Swift is a lot of fun to make new and exciting apps for Apple's App Store.

          </ColSM4>
          <ColSM4>

Android

Android is the most popular phone OS in the world, let's put an app on the Play Store

          </ColSM4>
        </Row>
      </Container>

        <Container>

Get in Touch

I'm available for freelance work. Contact me to move the conversation forward. We can discuss services and budget. Some of my services include web/app development, website maintenance, WordPress site customization, and WordPress maintenance

          <div dangerouslySetInnerHTML={{__html: 'Loading...'}} />
        </Container>

      <Container>
        <Row>
          <ColSM4>

Founder

Harrison McGuire

          </ColSM4>
          <ColSM4>

Email

harrison@severallevels.io

          </ColSM4>
          <ColSM4>

Location

Boca Raton, FL

          </ColSM4>
        </Row>

Where To Find Me

        <Row>

            Github

            YouTube

            Twitch

            Twitter

            Linkedin

        </Row>

Several Levels Productions, LLC is currently a one person LLC lead by Harrison McGuire.

      </Container>

export default IndexPage<commit_msg>small edit<commit_after>import React from 'react'
import Link from 'gatsby-link'
import Vivus from 'vivus'
import Tagline from '../components/Tagline'
import Header from '../components/Header'
import HeroText from '../components/HeroText'
import Container from '../components/utils/Container'
import Row from '../components/utils/Row'
import Col12 from '../components/utils/Col12'
import ColSM4 from '../components/utils/ColSM4'
import reactlogo from '../img/react-logo.svg'
import nodelogo from '../img/nodejs-logo.svg'
import wordpresslogo from '../img/wordpress-logo.svg'
import phplogo from '../img/php-logo.svg'
import shopifylogo from '../img/shopify-logo.svg'
import ioslogo from '../img/ios-logo.svg'
import androidlogo from '../img/android-logo.svg'

// TODO: put partial sections into react components and add portfolio section

const IndexPage = () =>

      <Container>
        <Row>
          <Col12>

Hi, welcome to several levels. My name is Harrison McGuire and I am the founder and lead software developer. I'm dedicated to making excellent, performant, modern websites.

          </Col12>
        </Row>

The Modern Web is Built with JavaScript

JavaScript has quickly taking over the web community with its versatility and vast range of powers

this site is made with React and Gatsby JS

        <Row>
          <ColSM4>
            <svg xmlns="http://www.w3.org/2000/svg" className="svg-logo mx-auto" viewBox="0 0 630 630">
              <rect width="630" height="630" fill="#f7df1e"/>
              <path d="m423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z"/>
            </svg>

JavaScript

The high-level programming language is extremely dynamic and powerful and I can make some magnificent software with JavaScript.

          </ColSM4>
          <ColSM4>

React

React is my preferred Javascript library. React’s flexibility and the component based structure makes it easy to work with while making extremely powerful apps.

          </ColSM4>
          <ColSM4>

NodeJS

NodeJS keeps my workflow in JavaScript and allows for apps to be built quickly and efficiently. Node is async by nature thus keeping sites running at optimal performance.

          </ColSM4>
        </Row>
      </Container>

      <HeroText>
        <Container>

several levels

web and app development

"I do things different striving for originality and modernity"

        </Container>
      </HeroText>

      <Container>

To Live and Breath With a CMS

CMS's can make the backend user experience incredible, but they can also add a lot of weight and unnecessary code to the project. I customize CMS themes to ensure great performance and user accessibility

        <Row>
          <ColSM4>

WordPress

I make custom themes and plugins for the world's most popular CMS.

          </ColSM4>
          <ColSM4>

PHP

PHP is the backbone of most of the world's servers that powers a majority of websites. PHP is necessary for all WordPress configurations.

          </ColSM4>
          <ColSM4>

Shopify

Shopify is my preferred ecommerce platform. I customize themes and generate dynamic front facing stores.

          </ColSM4>
        </Row>
      </Container>

      <HeroText>
        <Container>

"having the world's information in your pocket takes unrelenting responsibility"

        </Container>
      </HeroText>

      <Container>

The World in Our Pocket

app development can directly bring prodcuts to a user's hands

        <Row>
          <ColSM4>

iOS

I develop iOS apps with Swift. Swift is a lot of fun to make new and exciting apps for Apple's App Store.

          </ColSM4>
          <ColSM4>

Android

Android is the most popular phone OS in the world, let's put an app on the Play Store

          </ColSM4>
        </Row>
      </Container>

        <Container>

Get in Touch

I'm available for freelance work. Contact me to move the conversation forward. We can discuss services and budget. Some of my services include web/app development, website maintenance, WordPress site customization, and WordPress maintenance

          <div dangerouslySetInnerHTML={{__html: 'Loading...'}} />
        </Container>

      <Container>
        <Row>
          <ColSM4>

Founder

Harrison McGuire

          </ColSM4>
          <ColSM4>

Email

harrison@severallevels.io

          </ColSM4>
          <ColSM4>

Location

Boca Raton, FL

          </ColSM4>
        </Row>

Where To Find Me

        <Row>

            Github

            YouTube

            Twitch

            Twitter

            Linkedin

        </Row>

Several Levels Productions, LLC is currently a one person LLC lead by Harrison McGuire.

      </Container>

export default IndexPage<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');

var angular = require('camunda-bpm-sdk-js/vendor/angular'),

    Viewer = require('../../util/viewer'),

    template = fs.readFileSync(__dirname + '/cam-widget-bpmn-viewer.html', 'utf8');

module.exports = ['$q', '$document', '$compile', '$location', '$rootScope', 'search', 'debounce',
  function($q, $document, $compile,   $location,   $rootScope,   search, debounce) {

    return {
      scope: {
        diagramData: '=',
        key: '@',
        control: '=?',
        disableNavigation: '&',
        onLoad: '&',
        onClick: '&',
        onMouseEnter: '&',
        onMouseLeave: '&'
      },

      template: template,

      link: function($scope, $element) {

        var definitions;
        var diagramContainer = $element[0].querySelector('.diagram-holder');

        function attachDiagram() {
          diagramContainer.appendChild(viewer.container);
        }

        function detatchDiagram() {
          diagramContainer.removeChild(viewer.container);
        }

        $scope.grabbing = false;

        // parse boolean
        $scope.disableNavigation = $scope.$eval($scope.disableNavigation);

        // --- CONTROL FUNCTIONS ---
        $scope.control = $scope.control || {};

        $scope.control.highlight = function(id) {
          canvas.addMarker(id, 'highlight');

          $element.find('[data-element-id="'+id+'"]>.djs-outline').attr({
            rx: '14px',
            ry: '14px'
          });
        };

        $scope.control.clearHighlight = function(id) {
          canvas.removeMarker(id, 'highlight');
        };

        $scope.control.isHighlighted = function(id) {
          return canvas.hasMarker(id, 'highlight');
        };

        // config: text, tooltip, color, position
        $scope.control.createBadge = function(id, config) {
          var overlays = viewer.get('overlays');

          var htmlElement;
          if(config.html) {
            htmlElement = config.html;
          } else {
            htmlElement = document.createElement('span');
            if(config.color) {
              htmlElement.style['background-color'] = config.color;
            }
            if(config.tooltip) {
              htmlElement.setAttribute('tooltip', config.tooltip);
              htmlElement.setAttribute('tooltip-placement', 'top');
            }
            if(config.text) {
              htmlElement.appendChild(document.createTextNode(config.text));
            }
          }

          var overlayId = overlays.add(id, {
            position: config.position || {
              bottom: 0,
              right: 0
            },
            show: {
              minZoom: -Infinity,
              maxZoom: +Infinity
            },
            html: htmlElement
          });

          $compile(htmlElement)($scope);

          return overlayId;
        };

        // removes all badges for an element with a given id
        $scope.control.removeBadges = function(id) {
          viewer.get('overlays').remove({element:id});
        };

        // removes a single badge with a given id
        $scope.control.removeBadge = function(id) {
          viewer.get('overlays').remove(id);
        };

        $scope.control.getViewer = function() {
          return viewer;
        };

        $scope.control.scrollToElement = function(element) {
          var height, width, x, y;

          var elem = viewer.get('elementRegistry').get(element);
          var viewbox = canvas.viewbox();

          height = Math.max(viewbox.height, elem.height);
          width  = Math.max(viewbox.width,  elem.width);

          x = Math.min(Math.max(viewbox.x, elem.x - viewbox.width + elem.width), elem.x);
          y = Math.min(Math.max(viewbox.y, elem.y - viewbox.height + elem.height), elem.y);

          canvas.viewbox({
            x: x,
            y: y,
            width: width,
            height: height
          });
        };

        $scope.control.getElement = function(elementId) {
          return viewer.get('elementRegistry').get(elementId);
        };

        $scope.control.getElements = function(filter) {
          return viewer.get('elementRegistry').filter(filter);
        };

        $scope.loaded = false;
        $scope.control.isLoaded = function() {
          return $scope.loaded;
        };

        $scope.control.addAction = function(config) {
          var container = $element.find('.actions');
          var htmlElement = config.html;
          container.append(htmlElement);
          $compile(htmlElement)($scope);
        };

        var heatmapImage;

        $scope.control.addImage = function(image, x, y) {
          return preloadImage(image)
            .then(
              function(preloadedElement) {
                var width = preloadedElement.offsetWidth;
                var height = preloadedElement.offsetHeight;
                var imageElement = $document[0].createElementNS('http://www.w3.org/2000/svg', 'image');

                imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', image);
                imageElement.setAttributeNS(null, 'width', width);
                imageElement.setAttributeNS(null, 'height', height);
                imageElement.setAttributeNS(null, 'x', x);
                imageElement.setAttributeNS(null, 'y', y);

                $document[0].body.removeChild(preloadedElement);
                canvas._viewport.appendChild(imageElement);

                heatmapImage = angular.element(imageElement);
                return heatmapImage;
              },
              function(preloadedElement) {
                $document[0].body.removeChild(preloadedElement);
              }
            );
        };

        function preloadImage(img) {
          var body = $document[0].body;
          var deferred = $q.defer();
          var imageElement = angular.element('<img>')
            .css('position', 'absolute')
            .css('left', '-9999em')
            .css('top', '-9999em')
            .attr('src', img)[0];

          imageElement.onload = function() {
            deferred.resolve(imageElement);
          };

          imageElement.onerror = function() {
            deferred.reject(imageElement);
          };

          body.appendChild(imageElement);

          return deferred.promise;
        }

        function clearHeatmapImage() {
          if(heatmapImage && document.body.contains(heatmapImage[0])) {
            heatmapImage[0].parentNode.removeChild(heatmapImage[0]);
          }
        }

        var viewer = Viewer.generateViewer({
          width: '100%',
          height: '100%',
          canvas: {
            deferUpdate: false
          },
          key: $scope.key,
          disableNavigation: $scope.disableNavigation
        });

        if(!viewer.cached) {
          // attach diagram immediately to avoid having the bpmn logo for viewers that are not cached
          attachDiagram();
        }

        // The following logic mirrors diagram-js to defer its update of the viewbox change.
        // We tell diagram-js to not defer the update (see above) and do it ourselves instead.
        // Only difference: We use a delay of 0. This causes the update to basically be propagated
        // immediately after the current execution is finished (instead of halting the execution
        // until the viewbox changes and all event listeners are executed). This results in a much
        // better performance while moving the diagram, but at a cost: In the interval between the
        // trigger of the viewbox change and the calculation of the event handlers in the debounced
        // execution, things like badges or migration arrows are at the wrong position; they feel
        // like they are "dragged behind". Therefore, we temporarily hide the overlays.

        // patch show and hide of overlays
        var originalShow = viewer.get('overlays').show.bind(viewer.get('overlays'));
        viewer.get('overlays').show = function() {
          viewer.get('eventBus').fire('overlays.show');
          originalShow();
        };

        var originalHide = viewer.get('overlays').hide.bind(viewer.get('overlays'));
        viewer.get('overlays').hide = function() {
          viewer.get('eventBus').fire('overlays.hide');
          originalHide();
        };

        var showAgain = debounce(function() {
          viewer.get('overlays').show();
        }, 300);

        var originalViewboxChanged = viewer.get('canvas')._viewboxChanged.bind(viewer.get('canvas'));
        var debouncedOriginal = debounce(function() {
          originalViewboxChanged();
          viewer.get('overlays').hide();
          showAgain();
        }, 0);
        viewer.get('canvas')._viewboxChanged = function() {
          debouncedOriginal();
        };

        var diagramData = null;
        var canvas = null;

        $scope.$watch('diagramData', function(newValue) {
          if (newValue) {
            diagramData = newValue;
            renderDiagram();
          }
        });

        function handleViewerLoad() {
          canvas = viewer.get('canvas');
          definitions = viewer.definitions;
          setupEventListeners();
          zoom();
          $scope.loaded = true;
        }

        function renderDiagram() {
          // if there is a cached viewer, no need to import data
          if(viewer.cached) {
            attachDiagram();
            handleViewerLoad();
            return $scope.onLoad();

          } else if (diagramData) {
            $scope.loaded = false;

            var useDefinitions = (typeof diagramData === 'object');

            var importFunction = (useDefinitions ? viewer.importDefinitions : viewer.importXML).bind(viewer);

            importFunction(diagramData, function(err, warn) {

              var applyFunction = useDefinitions ? function(fn) {fn();} : $scope.$apply.bind($scope);

              applyFunction(function() {
                if (err) {
                  $scope.error = err;
                  return;
                }

                $scope.warn = warn;

                handleViewerLoad();
                return $scope.onLoad();
              });
            });

          }

        }

        function zoom() {
          if (canvas) {
            var viewbox = JSON.parse(($location.search() || {}).viewbox || '{}')[definitions.id];

            if (viewbox) {
              canvas.viewbox(viewbox);
            }
            else {
              canvas.zoom('fit-viewport', 'auto');
            }
          }
        }

        var mouseReleaseCallback = function() {
          $scope.grabbing = false;
          document.removeEventListener('mouseup', mouseReleaseCallback);
          $scope.$apply();
        };

        function onClick(e) {
          // e.element = the model element
          // e.gfx = the graphical element
          $scope.onClick({element: e.element, $event: e.originalEvent});
        }

        function onHover(e) {
          $scope.onMouseEnter({element: e.element, $event: e.originalEvent});
        }

        function onOut(e) {
          $scope.onMouseLeave({element: e.element, $event: e.originalEvent});
        }

        function onMousedown() {
          $scope.grabbing = true;
          document.addEventListener('mouseup', mouseReleaseCallback);
          $scope.$apply();
        }

        var onViewboxChange = debounce(function(e) {
          var viewbox = JSON.parse(($location.search() || {}).viewbox || '{}');

          viewbox[definitions.id] = {
            x: e.viewbox.x,
            y: e.viewbox.y,
            width: e.viewbox.width,
            height: e.viewbox.height
          };

          search.updateSilently({
            viewbox: JSON.stringify(viewbox)
          });

          var phase = $rootScope.$$phase;
          if (phase !== '$apply' && phase !== '$digest') {
            $scope.$apply(function() {
              $location.replace();
            });
          } else {
            $location.replace();
          }
        }, 500);

        function setupEventListeners() {
          var eventBus = viewer.get('eventBus');
          eventBus.on('element.click', onClick);
          eventBus.on('element.hover', onHover);
          eventBus.on('element.out', onOut);
          eventBus.on('element.mousedown', onMousedown);
          eventBus.on('canvas.viewbox.changed', onViewboxChange);
        }

        function clearEventListeners() {
          var eventBus = viewer.get('eventBus');
          eventBus.off('element.click', onClick);
          eventBus.off('element.hover', onHover);
          eventBus.off('element.out', onOut);
          eventBus.off('element.mousedown', onMousedown);
          eventBus.off('canvas.viewbox.changed', onViewboxChange);
        }

        $scope.zoomIn = function() {
          viewer.get('zoomScroll').zoom(1, {
            x: $element[0].offsetWidth / 2,
            y: $element[0].offsetHeight / 2
          });
        };

        $scope.zoomOut = function() {
          viewer.get('zoomScroll').zoom(-1, {
            x: $element[0].offsetWidth / 2,
            y: $element[0].offsetHeight / 2
          });
        };

        $scope.resetZoom = function() {
          canvas.resized();
          canvas.zoom('fit-viewport', 'auto');
        };

        $scope.control.resetZoom = $scope.resetZoom;

        $scope.control.refreshZoom = function() {
          canvas.resized();
          canvas.zoom(canvas.zoom(), 'auto');
        };

        $scope.$on('$destroy', function() {
          clearHeatmapImage();
          detatchDiagram();
          clearEventListeners();
          viewer.get('overlays').clear();
          Viewer.cacheViewer({ key: $scope.key, viewer: viewer });
        });

      }
    };
  }];
<commit_msg>chore(bpmn-viewer): remove heatmap logic from viewer<commit_after>'use strict';
var fs = require('fs');

var angular = require('camunda-bpm-sdk-js/vendor/angular'),

    Viewer = require('../../util/viewer'),

    template = fs.readFileSync(__dirname + '/cam-widget-bpmn-viewer.html', 'utf8');

module.exports = ['$q', '$document', '$compile', '$location', '$rootScope', 'search', 'debounce',
  function($q, $document, $compile,   $location,   $rootScope,   search, debounce) {

    return {
      scope: {
        diagramData: '=',
        key: '@',
        control: '=?',
        disableNavigation: '&',
        onLoad: '&',
        onClick: '&',
        onMouseEnter: '&',
        onMouseLeave: '&'
      },

      template: template,

      link: function($scope, $element) {

        var definitions;
        var diagramContainer = $element[0].querySelector('.diagram-holder');

        function attachDiagram() {
          diagramContainer.appendChild(viewer.container);
        }

        function detatchDiagram() {
          diagramContainer.removeChild(viewer.container);
        }

        $scope.grabbing = false;

        // parse boolean
        $scope.disableNavigation = $scope.$eval($scope.disableNavigation);

        // --- CONTROL FUNCTIONS ---
        $scope.control = $scope.control || {};

        $scope.control.highlight = function(id) {
          canvas.addMarker(id, 'highlight');

          $element.find('[data-element-id="'+id+'"]>.djs-outline').attr({
            rx: '14px',
            ry: '14px'
          });
        };

        $scope.control.clearHighlight = function(id) {
          canvas.removeMarker(id, 'highlight');
        };

        $scope.control.isHighlighted = function(id) {
          return canvas.hasMarker(id, 'highlight');
        };

        // config: text, tooltip, color, position
        $scope.control.createBadge = function(id, config) {
          var overlays = viewer.get('overlays');

          var htmlElement;
          if(config.html) {
            htmlElement = config.html;
          } else {
            htmlElement = document.createElement('span');
            if(config.color) {
              htmlElement.style['background-color'] = config.color;
            }
            if(config.tooltip) {
              htmlElement.setAttribute('tooltip', config.tooltip);
              htmlElement.setAttribute('tooltip-placement', 'top');
            }
            if(config.text) {
              htmlElement.appendChild(document.createTextNode(config.text));
            }
          }

          var overlayId = overlays.add(id, {
            position: config.position || {
              bottom: 0,
              right: 0
            },
            show: {
              minZoom: -Infinity,
              maxZoom: +Infinity
            },
            html: htmlElement
          });

          $compile(htmlElement)($scope);

          return overlayId;
        };

        // removes all badges for an element with a given id
        $scope.control.removeBadges = function(id) {
          viewer.get('overlays').remove({element:id});
        };

        // removes a single badge with a given id
        $scope.control.removeBadge = function(id) {
          viewer.get('overlays').remove(id);
        };

        $scope.control.getViewer = function() {
          return viewer;
        };

        $scope.control.scrollToElement = function(element) {
          var height, width, x, y;

          var elem = viewer.get('elementRegistry').get(element);
          var viewbox = canvas.viewbox();

          height = Math.max(viewbox.height, elem.height);
          width  = Math.max(viewbox.width,  elem.width);

          x = Math.min(Math.max(viewbox.x, elem.x - viewbox.width + elem.width), elem.x);
          y = Math.min(Math.max(viewbox.y, elem.y - viewbox.height + elem.height), elem.y);

          canvas.viewbox({
            x: x,
            y: y,
            width: width,
            height: height
          });
        };

        $scope.control.getElement = function(elementId) {
          return viewer.get('elementRegistry').get(elementId);
        };

        $scope.control.getElements = function(filter) {
          return viewer.get('elementRegistry').filter(filter);
        };

        $scope.loaded = false;
        $scope.control.isLoaded = function() {
          return $scope.loaded;
        };

        $scope.control.addAction = function(config) {
          var container = $element.find('.actions');
          var htmlElement = config.html;
          container.append(htmlElement);
          $compile(htmlElement)($scope);
        };

        var heatmapImage;

        $scope.control.addImage = function(image, x, y) {
          return preloadImage(image)
            .then(
              function(preloadedElement) {
                var width = preloadedElement.offsetWidth;
                var height = preloadedElement.offsetHeight;
                var imageElement = $document[0].createElementNS('http://www.w3.org/2000/svg', 'image');

                imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', image);
                imageElement.setAttributeNS(null, 'width', width);
                imageElement.setAttributeNS(null, 'height', height);
                imageElement.setAttributeNS(null, 'x', x);
                imageElement.setAttributeNS(null, 'y', y);

                $document[0].body.removeChild(preloadedElement);
                canvas._viewport.appendChild(imageElement);

                heatmapImage = angular.element(imageElement);
                return heatmapImage;
              },
              function(preloadedElement) {
                $document[0].body.removeChild(preloadedElement);
              }
            );
        };

        function preloadImage(img) {
          var body = $document[0].body;
          var deferred = $q.defer();
          var imageElement = angular.element('<img>')
            .css('position', 'absolute')
            .css('left', '-9999em')
            .css('top', '-9999em')
            .attr('src', img)[0];

          imageElement.onload = function() {
            deferred.resolve(imageElement);
          };

          imageElement.onerror = function() {
            deferred.reject(imageElement);
          };

          body.appendChild(imageElement);

          return deferred.promise;
        }

        var viewer = Viewer.generateViewer({
          width: '100%',
          height: '100%',
          canvas: {
            deferUpdate: false
          },
          key: $scope.key,
          disableNavigation: $scope.disableNavigation
        });

        if(!viewer.cached) {
          // attach diagram immediately to avoid having the bpmn logo for viewers that are not cached
          attachDiagram();
        }

        // The following logic mirrors diagram-js to defer its update of the viewbox change.
        // We tell diagram-js to not defer the update (see above) and do it ourselves instead.
        // Only difference: We use a delay of 0. This causes the update to basically be propagated
        // immediately after the current execution is finished (instead of halting the execution
        // until the viewbox changes and all event listeners are executed). This results in a much
        // better performance while moving the diagram, but at a cost: In the interval between the
        // trigger of the viewbox change and the calculation of the event handlers in the debounced
        // execution, things like badges or migration arrows are at the wrong position; they feel
        // like they are "dragged behind". Therefore, we temporarily hide the overlays.

        // patch show and hide of overlays
        var originalShow = viewer.get('overlays').show.bind(viewer.get('overlays'));
        viewer.get('overlays').show = function() {
          viewer.get('eventBus').fire('overlays.show');
          originalShow();
        };

        var originalHide = viewer.get('overlays').hide.bind(viewer.get('overlays'));
        viewer.get('overlays').hide = function() {
          viewer.get('eventBus').fire('overlays.hide');
          originalHide();
        };

        var showAgain = debounce(function() {
          viewer.get('overlays').show();
        }, 300);

        var originalViewboxChanged = viewer.get('canvas')._viewboxChanged.bind(viewer.get('canvas'));
        var debouncedOriginal = debounce(function() {
          originalViewboxChanged();
          viewer.get('overlays').hide();
          showAgain();
        }, 0);
        viewer.get('canvas')._viewboxChanged = function() {
          debouncedOriginal();
        };

        var diagramData = null;
        var canvas = null;

        $scope.$watch('diagramData', function(newValue) {
          if (newValue) {
            diagramData = newValue;
            renderDiagram();
          }
        });

        function handleViewerLoad() {
          canvas = viewer.get('canvas');
          definitions = viewer.definitions;
          setupEventListeners();
          zoom();
          $scope.loaded = true;
        }

        function renderDiagram() {
          // if there is a cached viewer, no need to import data
          if(viewer.cached) {
            attachDiagram();
            handleViewerLoad();
            return $scope.onLoad();

          } else if (diagramData) {
            $scope.loaded = false;

            var useDefinitions = (typeof diagramData === 'object');

            var importFunction = (useDefinitions ? viewer.importDefinitions : viewer.importXML).bind(viewer);

            importFunction(diagramData, function(err, warn) {

              var applyFunction = useDefinitions ? function(fn) {fn();} : $scope.$apply.bind($scope);

              applyFunction(function() {
                if (err) {
                  $scope.error = err;
                  return;
                }

                $scope.warn = warn;

                handleViewerLoad();
                return $scope.onLoad();
              });
            });

          }

        }

        function zoom() {
          if (canvas) {
            var viewbox = JSON.parse(($location.search() || {}).viewbox || '{}')[definitions.id];

            if (viewbox) {
              canvas.viewbox(viewbox);
            }
            else {
              canvas.zoom('fit-viewport', 'auto');
            }
          }
        }

        var mouseReleaseCallback = function() {
          $scope.grabbing = false;
          document.removeEventListener('mouseup', mouseReleaseCallback);
          $scope.$apply();
        };

        function onClick(e) {
          // e.element = the model element
          // e.gfx = the graphical element
          $scope.onClick({element: e.element, $event: e.originalEvent});
        }

        function onHover(e) {
          $scope.onMouseEnter({element: e.element, $event: e.originalEvent});
        }

        function onOut(e) {
          $scope.onMouseLeave({element: e.element, $event: e.originalEvent});
        }

        function onMousedown() {
          $scope.grabbing = true;
          document.addEventListener('mouseup', mouseReleaseCallback);
          $scope.$apply();
        }

        var onViewboxChange = debounce(function(e) {
          var viewbox = JSON.parse(($location.search() || {}).viewbox || '{}');

          viewbox[definitions.id] = {
            x: e.viewbox.x,
            y: e.viewbox.y,
            width: e.viewbox.width,
            height: e.viewbox.height
          };

          search.updateSilently({
            viewbox: JSON.stringify(viewbox)
          });

          var phase = $rootScope.$$phase;
          if (phase !== '$apply' && phase !== '$digest') {
            $scope.$apply(function() {
              $location.replace();
            });
          } else {
            $location.replace();
          }
        }, 500);

        function setupEventListeners() {
          var eventBus = viewer.get('eventBus');
          eventBus.on('element.click', onClick);
          eventBus.on('element.hover', onHover);
          eventBus.on('element.out', onOut);
          eventBus.on('element.mousedown', onMousedown);
          eventBus.on('canvas.viewbox.changed', onViewboxChange);
        }

        function clearEventListeners() {
          var eventBus = viewer.get('eventBus');
          eventBus.off('element.click', onClick);
          eventBus.off('element.hover', onHover);
          eventBus.off('element.out', onOut);
          eventBus.off('element.mousedown', onMousedown);
          eventBus.off('canvas.viewbox.changed', onViewboxChange);
        }

        $scope.zoomIn = function() {
          viewer.get('zoomScroll').zoom(1, {
            x: $element[0].offsetWidth / 2,
            y: $element[0].offsetHeight / 2
          });
        };

        $scope.zoomOut = function() {
          viewer.get('zoomScroll').zoom(-1, {
            x: $element[0].offsetWidth / 2,
            y: $element[0].offsetHeight / 2
          });
        };

        $scope.resetZoom = function() {
          canvas.resized();
          canvas.zoom('fit-viewport', 'auto');
        };

        $scope.control.resetZoom = $scope.resetZoom;

        $scope.control.refreshZoom = function() {
          canvas.resized();
          canvas.zoom(canvas.zoom(), 'auto');
        };

        $scope.$on('$destroy', function() {
          detatchDiagram();
          clearEventListeners();
          viewer.get('overlays').clear();
          Viewer.cacheViewer({ key: $scope.key, viewer: viewer });
        });

      }
    };
  }];
<|endoftext|>


<commit_before>var _ = require('underscore')
,   async = require('async')
,   redis = require('redis')
,   reds = require('reds')
,   kue = require('kue')

,   __init = false

,   JOBS, RED, CONF

/* TODO:
 *  Updating a job (or removing one in general) is unnecessarily slow.
 *  Optimize sometime later.
 *
 *  Removing requires 3 round-trips:
 *      - lookup ID -> kue_id
 *      - lookup job<kue_id>
 *      - remove job<kue_id>
 *
 *  Updating requires 2 more:
 *      - save new job
 *      - map new id
 */

function mapkey(jobType) {
  return ['q', 'idmap', jobType].join(':')
}

function utc_timestamp() {
    var d = new Date()
    return d.getTime() + (d.getTimezoneOffset() * 60 * 1000)
}

function INIT(config) {
  if (__init) return;

  CONF = config

  if (!! CONF.redis) {
    // TODO: avoid this hassle if https://github.com/LearnBoost/kue/issues/54
    //       ever gets fixed
    reds.createClient = function() {
      var client = redis.createClient(CONF.redis.port, CONF.redis.host)
      client.auth(CONF.redis.pass)
      return client
    }

    kue.redis.createClient = reds.createClient
  }

  JOBS = kue.createQueue()
  RED = JOBS.client

  JOBS.promote()

//  if (config.remove_completed)
//    JOBS.on('job complete', removeJob);

  __init = true
}

function removeJob(kid, $done) {
  $done = $done || function(){}
  kue.Job.get(kid, function(err, job) {
    if (err)
      return $done(err);
    else (job)
      job.remove($done);
  })
}

function removeMapped(jobType, id, $done) {
  RED.hget(mapkey(jobType), id, function(err, existing) {
    if (existing) {
      // TODO: should be able to use redis pipeline
      removeJob(existing, function(err) {
        if (err)
          $done(err);

        RED.hdel(mapkey(jobType), id, $done)
      })
    } else {
      $done(null, false)
    }
  })
}

var Q = function(config) {
  INIT(config)
}

_.extend(Q.prototype, {

  /* Params
   *    jobType: a <String> job type for kue
   *    id: our "custom" id for later reterival
   *    jobData: payload to be saved w/ job in redis
   *    [when]: a timestamp (in milliseconds) when the job should run (in UTC)
   *    $done: callback
   */
  push: function(envelope, $done) {
    function createJob(found, $_done) {
      if (found) {
        CONF.log.info('Removed old version of job ' + envelope.id)
      }

      var msg = '  creating job '+envelope.id+' '+ envelope.jobData.title + '...';
      CONF.log.info(msg)
      $_done(null, JOBS.create(envelope.jobType, envelope.jobData))
    }

    function saveJob(job, $_done) {
      // TODO: this is messy. clean up.
      function save($__done) {
        job.save($__done)
      }

      function mapID($__done) {
        if (envelope.id)
          RED.hset(mapkey(envelope.jobType), envelope.id, job.id, $__done);
        else
          $__done();
      }

      if (envelope.when)
        job.delay(parseInt(envelope.when, 10) - utc_timestamp());

      async.series([save, mapID], $_done)
    }

    // curry removeMapped, leaving only $callback to be passed
    var _removeMapped = _.bind(removeMapped, {},
                                 envelope.jobType, envelope.id)

    async.waterfall([_removeMapped, createJob, saveJob], $done)
  }

  ,remove: function(jobType, id, $done) {
    removeMapped(jobType, id, function(err) {
      if (err)
        return $done(err);

      var msg = 'Removed job "' + id + '"';
      CONF.log.info(msg)
      $done()
    })
  }

  ,process: function() {
    JOBS.process.apply(JOBS, arguments)
  }

  ,shutdown: function() {
    JOBS.shutdown.apply(JOBS, arguments)
  }

})

Q.kue = kue
Q._rawQueue = JOBS

module.exports = Q

<commit_msg>Set _rawQueue on each object instead of global Q<commit_after>var _ = require('underscore')
,   async = require('async')
,   redis = require('redis')
,   reds = require('reds')
,   kue = require('kue')

,   __init = false

,   JOBS, RED, CONF

/* TODO:
 *  Updating a job (or removing one in general) is unnecessarily slow.
 *  Optimize sometime later.
 *
 *  Removing requires 3 round-trips:
 *      - lookup ID -> kue_id
 *      - lookup job<kue_id>
 *      - remove job<kue_id>
 *
 *  Updating requires 2 more:
 *      - save new job
 *      - map new id
 */

function mapkey(jobType) {
  return ['q', 'idmap', jobType].join(':')
}

function utc_timestamp() {
    var d = new Date()
    return d.getTime() + (d.getTimezoneOffset() * 60 * 1000)
}

function INIT(config) {
  if (__init) return;

  CONF = config

  if (!! CONF.redis) {
    // TODO: avoid this hassle if https://github.com/LearnBoost/kue/issues/54
    //       ever gets fixed
    reds.createClient = function() {
      var client = redis.createClient(CONF.redis.port, CONF.redis.host)
      client.auth(CONF.redis.pass)
      return client
    }

    kue.redis.createClient = reds.createClient
  }

  JOBS = kue.createQueue()
  RED = JOBS.client

  JOBS.promote()

//  if (config.remove_completed)
//    JOBS.on('job complete', removeJob);

  __init = true
}

function removeJob(kid, $done) {
  $done = $done || function(){}
  kue.Job.get(kid, function(err, job) {
    if (err)
      return $done(err);
    else (job)
      job.remove($done);
  })
}

function removeMapped(jobType, id, $done) {
  RED.hget(mapkey(jobType), id, function(err, existing) {
    if (existing) {
      // TODO: should be able to use redis pipeline
      removeJob(existing, function(err) {
        if (err)
          $done(err);

        RED.hdel(mapkey(jobType), id, $done)
      })
    } else {
      $done(null, false)
    }
  })
}

var Q = function(config) {
  INIT(config)
  this._rawQueue = JOBS
}

_.extend(Q.prototype, {

  /* Params
   *    jobType: a <String> job type for kue
   *    id: our "custom" id for later reterival
   *    jobData: payload to be saved w/ job in redis
   *    [when]: a timestamp (in milliseconds) when the job should run (in UTC)
   *    $done: callback
   */
  push: function(envelope, $done) {
    function createJob(found, $_done) {
      if (found) {
        CONF.log.info('Removed old version of job ' + envelope.id)
      }

      var msg = '  creating job '+envelope.id+' '+ envelope.jobData.title + '...';
      CONF.log.info(msg)
      $_done(null, JOBS.create(envelope.jobType, envelope.jobData))
    }

    function saveJob(job, $_done) {
      // TODO: this is messy. clean up.
      function save($__done) {
        job.save($__done)
      }

      function mapID($__done) {
        if (envelope.id)
          RED.hset(mapkey(envelope.jobType), envelope.id, job.id, $__done);
        else
          $__done();
      }

      if (envelope.when)
        job.delay(parseInt(envelope.when, 10) - utc_timestamp());

      async.series([save, mapID], $_done)
    }

    // curry removeMapped, leaving only $callback to be passed
    var _removeMapped = _.bind(removeMapped, {},
                                 envelope.jobType, envelope.id)

    async.waterfall([_removeMapped, createJob, saveJob], $done)
  }

  ,remove: function(jobType, id, $done) {
    removeMapped(jobType, id, function(err) {
      if (err)
        return $done(err);

      var msg = 'Removed job "' + id + '"';
      CONF.log.info(msg)
      $done()
    })
  }

  ,process: function() {
    JOBS.process.apply(JOBS, arguments)
  }

  ,shutdown: function() {
    JOBS.shutdown.apply(JOBS, arguments)
  }

})

Q.kue = kue

module.exports = Q

<|endoftext|>


<commit_before>/**
 * BinaryReader.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/utils/BinaryReader
@private
*/
define("moxie/runtime/html5/utils/BinaryReader", [
	"moxie/core/utils/Basic",
], function(Basic) {

	function BinaryReader(data) {
		if (data instanceof ArrayBuffer) {
			ArrayBufferReader.apply(this, arguments);
		} else {
			UTF16StringReader.apply(this, arguments);
		}
	}

	Basic.extend(BinaryReader.prototype, {

		littleEndian: false,

		read: function(idx, size) {
			var sum, mv, i;

			if (idx + size > this.length()) {
				throw new Error("You are trying to read outside the source boundaries.");
			}

			mv = this.littleEndian
				? 0
				: -8 * (size - 1)
			;

			for (i = 0, sum = 0; i < size; i++) {
				sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8));
			}
			return sum;
		},

		BYTE: function(idx) {
			return this.read(idx, 1);
		},

		SHORT: function(idx) {
			return this.read(idx, 2);
		},

		LONG: function(idx) {
			return this.read(idx, 4);
		},

		SLONG: function(idx) { // 2's complement notation
			var num = this.read(idx, 4);
			return (num > 2147483647 ? num - 4294967296 : num);
		},

		CHAR: function(idx) {
			return String.fromCharCode(this.read(idx, 1));
		},

		clear: function() {}
	});

	function ArrayBufferReader(data) {
		var _dv = new DataView(data);

		Basic.extend(this, {

			readByteAt: function(idx) {
				return _dv.getUint8(idx);
			},

			write: function(idx, num, size) {
				var mv, i, str = '';

				if (idx > this.length()) {
					throw new Error("You are trying to write outside the source boundaries.");
				}

				mv = this.littleEndian
					? 0
					: -8 * (size - 1)
				;

				for (i = 0; i < size; i++) {
					_dv.setUint8(idx + i, (num >> Math.abs(mv + i*8)) & 255);
				}
			},

			SEGMENT: function(idx, size, value) {
				switch (arguments.length) {
					case 2:
						return data.slice(idx, idx + size);

					case 1:
						return data.slice(idx);

					case 3:
						if (value instanceof ArrayBuffer) {
							var arr = new Uint8Array(this.length() - size + value.byteLength);
							if (idx > 0) {
								arr.set(new Uint8Array(data.slice(0, idx)), 0);
							}
							arr.set(new Uint8Array(value), idx);
							arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength);

							this.clear();
							data = arr.buffer;
							_dv = new DataView(data);
							break;
						}

					default: return data;
				}
			},

			length: function() {
				return data ? data.byteLength : 0;
			},

			clear: function() {
				_dv = data = null;
			}
		});
	}

	function UTF16StringReader(data) {
		Basic.extend(this, {

			readByteAt: function(idx) {
				return data.charCodeAt(idx);
			},

			write: function(idx, num, size) {
				var mv, i, str = '';

				if (idx > this.length()) {
					throw new Error("You are trying to write outside the source boundaries.");
				}

				mv = this.littleEndian
					? 0
					: -8 * (size - 1)
				;

				for (i = 0; i < size; i++) {
					str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255);
				}

				putstr(str, idx, size);
			},

			SEGMENT: function(idx, length, segment) {
				switch (arguments.length) {
					case 1:
						return data.substr(idx);
					case 2:
						return data.substr(idx, length);
					case 3:
						putstr(segment, idx, length);
						break;
					default: return data;
				}
			},

			length: function() {
				return data ? data.length : 0;
			},

			clear: function() {
				data = null;
			}
		});

		function putstr(segment, idx, length) {
			length = arguments.length === 3 ? length : data.length - idx - 1;
			data = data.substr(0, idx) + segment + data.substr(length + idx);
		}
	}

	return BinaryReader;
});
<commit_msg>BinaryReader, HTML5: Handle null as third argument in SEGMENT().<commit_after>/**
 * BinaryReader.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/utils/BinaryReader
@private
*/
define("moxie/runtime/html5/utils/BinaryReader", [
	"moxie/core/utils/Basic",
], function(Basic) {

	function BinaryReader(data) {
		if (data instanceof ArrayBuffer) {
			ArrayBufferReader.apply(this, arguments);
		} else {
			UTF16StringReader.apply(this, arguments);
		}
	}

	Basic.extend(BinaryReader.prototype, {

		littleEndian: false,

		read: function(idx, size) {
			var sum, mv, i;

			if (idx + size > this.length()) {
				throw new Error("You are trying to read outside the source boundaries.");
			}

			mv = this.littleEndian
				? 0
				: -8 * (size - 1)
			;

			for (i = 0, sum = 0; i < size; i++) {
				sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8));
			}
			return sum;
		},

		BYTE: function(idx) {
			return this.read(idx, 1);
		},

		SHORT: function(idx) {
			return this.read(idx, 2);
		},

		LONG: function(idx) {
			return this.read(idx, 4);
		},

		SLONG: function(idx) { // 2's complement notation
			var num = this.read(idx, 4);
			return (num > 2147483647 ? num - 4294967296 : num);
		},

		CHAR: function(idx) {
			return String.fromCharCode(this.read(idx, 1));
		},

		clear: function() {}
	});

	function ArrayBufferReader(data) {
		var _dv = new DataView(data);

		Basic.extend(this, {

			readByteAt: function(idx) {
				return _dv.getUint8(idx);
			},

			write: function(idx, num, size) {
				var mv, i, str = '';

				if (idx > this.length()) {
					throw new Error("You are trying to write outside the source boundaries.");
				}

				mv = this.littleEndian
					? 0
					: -8 * (size - 1)
				;

				for (i = 0; i < size; i++) {
					_dv.setUint8(idx + i, (num >> Math.abs(mv + i*8)) & 255);
				}
			},

			SEGMENT: function(idx, size, value) {
				switch (arguments.length) {
					case 2:
						return data.slice(idx, idx + size);

					case 1:
						return data.slice(idx);

					case 3:
						if (value === null) {
							value = new ArrayBuffer();
						}

						if (value instanceof ArrayBuffer) {
							var arr = new Uint8Array(this.length() - size + value.byteLength);
							if (idx > 0) {
								arr.set(new Uint8Array(data.slice(0, idx)), 0);
							}
							arr.set(new Uint8Array(value), idx);
							arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength);

							this.clear();
							data = arr.buffer;
							_dv = new DataView(data);
							break;
						}

					default: return data;
				}
			},

			length: function() {
				return data ? data.byteLength : 0;
			},

			clear: function() {
				_dv = data = null;
			}
		});
	}

	function UTF16StringReader(data) {
		Basic.extend(this, {

			readByteAt: function(idx) {
				return data.charCodeAt(idx);
			},

			write: function(idx, num, size) {
				var mv, i, str = '';

				if (idx > this.length()) {
					throw new Error("You are trying to write outside the source boundaries.");
				}

				mv = this.littleEndian
					? 0
					: -8 * (size - 1)
				;

				for (i = 0; i < size; i++) {
					str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255);
				}

				putstr(str, idx, size);
			},

			SEGMENT: function(idx, length, segment) {
				switch (arguments.length) {
					case 1:
						return data.substr(idx);
					case 2:
						return data.substr(idx, length);
					case 3:
						putstr(segment !== null ? segment : '', idx, length);
						break;
					default: return data;
				}
			},

			length: function() {
				return data ? data.length : 0;
			},

			clear: function() {
				data = null;
			}
		});

		function putstr(segment, idx, length) {
			length = arguments.length === 3 ? length : data.length - idx - 1;
			data = data.substr(0, idx) + segment + data.substr(length + idx);
		}
	}

	return BinaryReader;
});
<|endoftext|>


<commit_before>/**
 * Edition field for a date - a text input with a datepicker.
 *
 * @example <ma-date-field field="field" value="value"></ma-date-field>
 */
export default function maDateField() {
    return {
        scope: {
            'field': '&',
            'value': '='
        },
        restrict: 'E',
        link: function(scope, element) {
            var field = scope.field();
            scope.name = field.name();
            scope.rawValue = scope.value == null ? null : (scope.value instanceof Date ? scope.value : new Date(scope.value));
            scope.$watch('rawValue', function(rawValue) {
                scope.value = field.parse()(rawValue);
            });
            scope.format = field.format();
            if (!scope.format) {
                scope.format = field.type() === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss';
            }

            scope.v = field.validation();
            scope.isOpen = false;
            var input = element.find('input').eq(0);
            var attributes = field.attributes();
            for (var name in attributes) {
                input.attr(name, attributes[name]);
            }
            scope.toggleDatePicker = function ($event) {
                $event.preventDefault();
                $event.stopPropagation();
                scope.isOpen = !scope.isOpen;
            };
        },
        template:
`

    <input
        type="text" ng-model="rawValue" id="{{ name }}" name="{{ name }}" class="form-control"
        uib-datepicker-popup="{{ format }}" is-open="isOpen" ng-required="v.required"
        close-text="{{ 'CLOSE' | translate }}" clear-text="{{ 'CLEAR' | translate }}" current-text="{{ 'CURRENT' | translate }}"/>

        <button type="button" class="btn btn-default" ng-click="toggleDatePicker($event)">

        </button>

`
    };
}

maDateField.$inject = [];
<commit_msg>fixing issue #899<commit_after>/**
 * Edition field for a date - a text input with a datepicker.
 *
 * @example <ma-date-field field="field" value="value"></ma-date-field>
 */
export default function maDateField() {
    return {
        scope: {
            'field': '&',
            'value': '='
        },
        restrict: 'E',
        link: function(scope, element) {
            var field = scope.field();
            scope.name = field.name();
            scope.rawValue = scope.value == null ? null : (scope.value instanceof Date ? scope.value : new Date(scope.value));
            scope.$watch('rawValue', function(rawValue) {
                scope.value = field.parse()(rawValue);
            });
            scope.$watch('value', function(rawValue) {
                scope.rawValue = scope.value == null ? null : (scope.value instanceof Date ? scope.value : new Date(scope.value));
            });
            scope.format = field.format();
            if (!scope.format) {
                scope.format = field.type() === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss';
            }

            scope.v = field.validation();
            scope.isOpen = false;
            var input = element.find('input').eq(0);

            var attributes = field.attributes();
            for (var name in attributes) {
                input.attr(name, attributes[name]);
            }
            scope.toggleDatePicker = function ($event) {
                $event.preventDefault();
                $event.stopPropagation();
                scope.isOpen = !scope.isOpen;
            };
        },
        template:
`

    <input
        type="text" ng-model="rawValue" id="{{ name }}" name="{{ name }}" class="form-control"
        uib-datepicker-popup="{{ format }}" is-open="isOpen" ng-required="v.required"
        close-text="{{ 'CLOSE' | translate }}" clear-text="{{ 'CLEAR' | translate }}" current-text="{{ 'CURRENT' | translate }}"/>

        <button type="button" class="btn btn-default" ng-click="toggleDatePicker($event)">

        </button>

`
    };
}

maDateField.$inject = [];
<|endoftext|>


<commit_before>CT.pubsub = {
	"_ws": null,
	"_open": false,
	"_queue": [],
	"_channels": {},
	"_cb_message": function() {}, // override w/ set_cb()
	"_cb_join": function() {}, // override w/ set_cb()
	"_cb_leave": function() {}, // override w/ set_cb()
	"_read": function(msg) {
		CT.pubsub["_read_" + msg.action](msg.data);
	},
	"_read_channel": function(data) {
		CT.pubsub._channels[data.channel] = data.users;
		data.history.forEach(CT.pubsub._read_publish);
	},
	"_read_publish": function(data) {
		CT.pubsub._cb_message(data.channel, data.user, data.message);
	},
	"_read_subscribe": function(data) {
		CT.pubsub._cb_join(data.channel, data.user);
		CT.pubsub._channels[data.channel].push(data.user);
	},
	"_read_unsubscribe": function(data) {
		CT.pubsub._cb_leave(data.channel, data.user);
		CT.data.remove(CT.pubsub._channels[data.channel], data.user);
	},
	"_register": function() {
		CT.pubsub._open = true;
		CT.pubsub._queue.forEach(CT.pubsub.write);
	},
	"set_cb": function(cb, action) { // action: message|join|leave
		CT.pubsub["_cb_" + action] = cb;
	},
	"write": function(data) {
		if (CT.pubsub._open) {
			var dstring = JSON.stringify(data);
			CT.pubsub._ws.send(dstring);
			console.log("WRITE", dstring);
		} else {
			CT.pubsub._queue.push(data);
			console.log("QUEUE", JSON.stringify(CT.pubsub._queue));
		}
	},
	"publish": function(channel, message) {
		CT.pubsub.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname) {
		CT.pubsub._ws = new WebSocket("ws://" + host + ":" + port);
		CT.pubsub._ws.onopen = CT.pubsub._register;
		CT.pubsub._ws.onmessage = CT.pubsub._read;
		CT.pubsub.write(uname);
	}
};<commit_msg>switched arg order of CT.pubsub.set_cb(). _read() JSON parses appropriate string on message object.<commit_after>CT.pubsub = {
	"_ws": null,
	"_open": false,
	"_queue": [],
	"_channels": {},
	"_cb_message": function() {}, // override w/ set_cb()
	"_cb_join": function() {}, // override w/ set_cb()
	"_cb_leave": function() {}, // override w/ set_cb()
	"_read": function(msg) {
		var d = JSON.parse(msg.data);
		CT.pubsub["_read_" + d.action](d.data);
	},
	"_read_channel": function(data) {
		CT.pubsub._channels[data.channel] = data.users;
		data.history.forEach(CT.pubsub._read_publish);
	},
	"_read_publish": function(data) {
		CT.pubsub._cb_message(data.channel, data.user, data.message);
	},
	"_read_subscribe": function(data) {
		CT.pubsub._cb_join(data.channel, data.user);
		CT.pubsub._channels[data.channel].push(data.user);
	},
	"_read_unsubscribe": function(data) {
		CT.pubsub._cb_leave(data.channel, data.user);
		CT.data.remove(CT.pubsub._channels[data.channel], data.user);
	},
	"_register": function() {
		CT.pubsub._open = true;
		CT.pubsub._queue.forEach(CT.pubsub.write);
	},
	"set_cb": function(action, cb) { // action: message|join|leave
		CT.pubsub["_cb_" + action] = cb;
	},
	"write": function(data) {
		if (CT.pubsub._open) {
			var dstring = JSON.stringify(data);
			CT.pubsub._ws.send(dstring);
			console.log("WRITE", dstring);
		} else {
			CT.pubsub._queue.push(data);
			console.log("QUEUE", JSON.stringify(CT.pubsub._queue));
		}
	},
	"publish": function(channel, message) {
		CT.pubsub.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname) {
		CT.pubsub._ws = new WebSocket("ws://" + host + ":" + port);
		CT.pubsub._ws.onopen = CT.pubsub._register;
		CT.pubsub._ws.onmessage = CT.pubsub._read;
		CT.pubsub.write(uname);
	}
};<|endoftext|>


<commit_before>import styled, { css } from 'styled-components';

import { focusStyle, inputStyle, placeholderStyle } from '../../utils';

const sizeStyle = props => {
  const data = props.theme.text[props.size];
  return css`
    font-size: ${data.size};
    line-height: ${data.height};
  `;
};

const plainStyle = css`
  border: none;
`;

export const StyledMaskedInput = styled.input`
  ${inputStyle} width: 100%;

  ${props => props.size && sizeStyle(props)} ${props =>
  props.plain && plainStyle}

  ${placeholderStyle}

  &::-moz-focus-inner {
    border: none;
    outline: none;
  }

  ${props => props.focus && !props.plain && focusStyle};
  ${props => props.theme.MaskedInput && props.theme.MaskedInput.extend};
`;

export const StyledMaskedInputContainer = styled.div`
  position: relative;
  width: 100%;
`;
<commit_msg>modify theme property name to extend MaskedInput component (#3135)<commit_after>import styled, { css } from 'styled-components';

import { focusStyle, inputStyle, placeholderStyle } from '../../utils';

const sizeStyle = props => {
  const data = props.theme.text[props.size];
  return css`
    font-size: ${data.size};
    line-height: ${data.height};
  `;
};

const plainStyle = css`
  border: none;
`;

export const StyledMaskedInput = styled.input`
  ${inputStyle} width: 100%;

  ${props => props.size && sizeStyle(props)} ${props =>
  props.plain && plainStyle}

  ${placeholderStyle}

  &::-moz-focus-inner {
    border: none;
    outline: none;
  }

  ${props => props.focus && !props.plain && focusStyle};
  ${props => props.theme.maskedInput && props.theme.maskedInput.extend};
`;

export const StyledMaskedInputContainer = styled.div`
  position: relative;
  width: 100%;
`;
<|endoftext|>


<commit_before>exports.handler = (event, context, callback) => {

	//try catch is for potential errors in code
	try {

		if (event.session.new) {
			// New Session
			console.log("NEW SESSION")
		}

		switch (event.request.type) {

			case "LaunchRequest":
				// Launch Request *** called if only invocation is called
				console.log('LAUNCH REQUEST')
				context.succeed(
					generateResponse(
						{},
						buildSpeechletResponse(
							"Welcome to Ferris' example Alexa. This runs on Lambda",true)
						)
					)
				break;

			case "IntentRequest":
				// Intent Request *** called if specified call is made to intent
				console.log('INTENT REQUEST')
				context.succeed(
					handleIntent(event.request, event.session),
						(sessionAttributes, speechletResponse=>
							callback(null, buildResponse(sessionAttributes, speechletResponse));
						});
					);

				break;

			case "SessionEndedRequest":
				// Session Ended Request *** called if code is exited
				console.log('SESSION ENDED REQUEST')
				break;

			default:
				context.fail('INVALID REQUEST TYPE: ${event.request.type}')

		}

	} catch(error) { context.fail('Exception: ${error}') }

}

// Helpers
buildSpeechletResponse = (outputText, shouldEndSession) => {

	return {
		outputSpeech: {
			type: "PlainText",
			text: outputText
		},
		shouldEndSession: shouldEndSession
	}
}

generateResponse = (sessionAttributes, speechletResponse) => {

	return {
		version: "1.0",
		sessionAttributes: sessionAttributes,
		response: speechletResponse
	}
}

handleIntent = (request, session, callback) => {
	console.log(`onIntent requestId=${intentRequest.requestId},
										sessionId=${session.sessionId}`);
	const intent = intentRequest.intent;
	const intentName = intent.name;

	if (intentName == /* INTENT NAME HERE */) {
		// call intent function
		// function(intent, session, callback) or
		// function(callback)
	} else if (intentName === 'AMAZON.HelpIntent') {
        // function here
    } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
        // function here
    } else {
        throw new Error('Invalid intent');
    }

}<commit_msg>expanded buildSpeechletResponse, started getInfo intent function<commit_after>exports.handler = (event, context, callback) => {

	//try catch is for potential errors in code
	try {

		if (event.session.new) {
			// New Session
			console.log("NEW SESSION")
		}

		switch (event.request.type) {

			case "LaunchRequest":
				// Launch Request *** called if only invocation is called
				console.log('LAUNCH REQUEST')
				context.succeed(
					generateResponse(
						{},
						buildSpeechletResponse(
							event.request.intent.name,
							"Welcome to Ferris' example Alexa. This runs on Lambda",
							"", true)
						)
					)
				break;

			case "IntentRequest":
				// Intent Request *** called if specified call is made to intent
				console.log('INTENT REQUEST')
				context.succeed(
					handleIntent(event.request, event.session),
						(sessionAttributes, speechletResponse=>
							callback(null, buildResponse(sessionAttributes, speechletResponse));
						});
					);

				break;

			case "SessionEndedRequest":
				// Session Ended Request *** called if code is exited
				console.log('SESSION ENDED REQUEST')
				break;

			default:
				context.fail('INVALID REQUEST TYPE: ${event.request.type}')

		}

	} catch(error) { context.fail('Exception: ${error}') }

}

// Helpers
buildSpeechletResponse = (title, outputText, repromptText, shouldEndSession) => {

	return {
		outputSpeech: {
			type: "PlainText",
			text: outputText
		},
		// Add for ability to communicate with phone app
		// card: {
        //     type: 'Simple',
        //     title: `SessionSpeechlet - ${title}`,
        //     content: `SessionSpeechlet - ${output}`,
        // },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
		shouldEndSession
	};
}

generateResponse = (sessionAttributes, speechletResponse) => {

	return {
		version: "1.0",
		sessionAttributes: sessionAttributes,
		response: speechletResponse
	}
}

handleIntent = (request, session, callback) => {
	console.log(`onIntent requestId=${intentRequest.requestId},
										sessionId=${session.sessionId}`);
	const intent = intentRequest.intent;
	const intentName = intent.name;

	// if (intentName == /* INTENT NAME HERE */) {
		// call intent function
		// function(intent, session, callback) or
		// function(callback)
	// }
	if (intentName == 'getInfo') {
		getInfo(intent, session, callback);
	} else if (intentName === 'AMAZON.HelpIntent') {
        // function here
    } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
        // function here
    } else {
        throw new Error('Invalid intent');
    }

}

/// /  intents  / ///

getInfo = (intent, session, callback) => {
	const cardTitle = intent.name;
	const personSlot = intent.slots.Person;
	const endSession = false;
	const reprompt = '';
	let sessionAttributes = {};
	let response = '';

	if (personSlot) {
		const person = personSlot.value;

		response = '${person} is an American hero.';
	} else {
		response = 'Please specify a person.';
	}

	callback(sessionAttributes, buildSpeechletResponse(cardTitle,
				response, reprompt, endSession));
}

/// /           / ///<|endoftext|>


<commit_before>import React from 'react';

import ConfigurationView from './ConfigurationView';
import Service from '../structs/Service';

class ServiceDetailConfigurationTab extends React.Component {

  render() {
    let {service} = this.props;
    let {currentVersionID} = service.getVersionInfo();

    return (
      <ConfigurationView
        headline={`Current Version (${currentVersionID})`}
        service={service}
        versionID={currentVersionID} />
    );
  }

}

ServiceDetailConfigurationTab.propTypes = {
  service: React.PropTypes.instanceOf(Service).isRequired
};

module.exports = ServiceDetailConfigurationTab;
<commit_msg>Add version dropdown to configuration with apply logic<commit_after>import {Dropdown} from 'reactjs-components';
import React from 'react';

import ConfigurationView from './ConfigurationView';
import DCOSStore from '../stores/DCOSStore';
import Service from '../structs/Service';

const METHODS_TO_BIND = [
  'handleVersionSelection'
];

class ServiceDetailConfigurationTab extends React.Component {
  constructor() {
    super();

    this.state = {
      selectedVersionID: null
    };

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillMount() {
    this.setState({
      selectedVersionID: this.props.service.getVersion()
    });
    DCOSStore.fetchServiceVersions(this.props.service.getId());
  }

  handleVersionSelection(versionItem) {
    this.setState({
      selectedVersionID: versionItem.id
    });
  }

  getVersionsDropdown() {
    let {service} = this.props;
    let versions = service.getVersions();

    if (versions.size < 2) {
      return null;
    }

    let versionItems = [];
    for (let version of versions.keys()) {
      let itemCaption = version;
      if (version === service.getVersion()) {
        itemCaption = `Current version ${version}`;
      }

      versionItems.push({
        id: version,
        html: (

            {itemCaption}

        )
      });
    }

    return (
      <Dropdown
        buttonClassName="button button-inverse dropdown-toggle button-split-content"
        dropdownMenuClassName="dropdown-menu inverse"
        dropdownMenuListClassName="dropdown-menu-list"
        dropdownMenuListItemClassName="clickable"
        items={versionItems}
        onItemSelection={this.handleVersionSelection}
        persistentID={this.state.selectedVersionID}
        transition={true}
        transitionName="dropdown-menu"
        wrapperClassName="dropdown" />
     );
  }

  render() {
    let {service} = this.props;
    let {selectedVersionID} = this.state;

    let headline = `Current Version (${selectedVersionID})`;

    if (service.getVersion() !== selectedVersionID) {
      headline = `Version (${selectedVersionID})`;
    }

    return (

        {this.getVersionsDropdown()}
        <ConfigurationView
          headline={headline}
          service={service}
          versionID={selectedVersionID} />

    );
  }

}

ServiceDetailConfigurationTab.propTypes = {
  service: React.PropTypes.instanceOf(Service).isRequired
};

module.exports = ServiceDetailConfigurationTab;
<|endoftext|>


<commit_before>const apiRoutes = require('../../../api')
const browser = require('../../../browser')
const querystring = require('../../../get-url-parameter')

const ko = require('knockout')
const htmlEncode = require('htmlencode')
const marked = require('marked')
marked.setOptions({ sanitize: true })

export const buildFindHelpUrl = (locationResult, range = querystring.parameter('range')) => {
  const re = new RegExp(/find-help\/(.*)\//)
  const category = browser.location().pathname.match(re)[1]
  return apiRoutes.servicesByCategory +
    category + '/' +
    locationResult.latitude + '/' +
    locationResult.longitude +
    '?range=' + range
}

export const getSubCategories = (providers) => {
  const toJustSubCats = (accumulator, provider) => [...accumulator, ...provider.subCategories]
  const toUnique = (acc, subcat) => {
    const match = acc.find((sc) => sc.id === subcat.id)
    const result = match === undefined
      ? [...acc, subcat]
      : acc
    return result
  }

  return providers
    .reduce(toJustSubCats, [])
    .reduce(toUnique, [])
    .sort((a, b) => {
      if (a.name < b.name) return -1
      if (a.name > b.name) return 1
      return 0
    })
}

const hasLocationDescription = (description) => {
  return description !== null && description !== undefined && description.length > 0
}

export const getProvidersForListing = (providers) => {
  const groupOpeningTimes = (ungrouped) => {
    const toDictionary = (acc, curr) => {
      if (acc[curr.day] === undefined) {
        acc[curr.day] = [curr.startTime + '-' + curr.endTime]
      } else {
        acc[curr.day] = [...acc[curr.day], curr.startTime + '-' + curr.endTime]
      }
      return acc
    }

    const toDataStructure = (day) => {
      return {
        day: day,
        openingTimes: groupedByDay[day]
      }
    }

    const groupedByDay = ungrouped
      .reduce(toDictionary, {})

    return Object.keys(groupedByDay)
      .map(toDataStructure)
  }

  const extractService = (provider) => {
    const getFullAddress = (location) => {
      return htmlEncode.htmlDecode(`${[location.streetLine1, location.streetLine2, location.streetLine3, location.streetLine4, location.city]
        .filter((l) => l !== null && l.length > 0)
        .map((l) => l.trim())
        .join(', ')}. ${location.postcode.toUpperCase()}`)
    }

    provider.location.locationDescription = provider.locationDescription
    return {
      info: marked(htmlEncode.htmlDecode(provider.info)),
      location: provider.location,
      hasLocationDescription: hasLocationDescription(provider.locationDescription),
      locationDescription: provider.locationDescription,
      fullAddress: getFullAddress(provider.location),
      viewMapsUrl: `https://www.google.co.uk/maps/place/${provider.location.postcode}`,
      hasTelephone: provider.telephone !== null,
      telephone: provider.telephone,
      days: groupOpeningTimes(provider.openingTimes),
      isOpen247: provider.isOpen247,
      isTelephoneService: provider.isTelephoneService,
      isAppointmentOnly: provider.isAppointmentOnly,
      subCategoryIds: provider.subCategories
        .map((sc) => sc.id)
        .join(' '),
      servicesAvailable: provider.subCategories
        .map((sc) => sc.name)
        .join(', ')
    }
  }

  const formatNewProvider = (id, providersDictionary) => {
    const services = providersDictionary[id]
      .map((p) => extractService(p))
    const subCategories = providersDictionary[id]
      .reduce((acc, currProvider) => {
        return [...acc, ...currProvider.subCategories]
      }, [])

    const [head, ...tail] = providersDictionary[id] // eslint-disable-line

    const data = {
      providerId: head.serviceProviderId,
      providerName: htmlEncode.htmlDecode(head.serviceProviderName),
      providerPageUrl: `/find-help/organisation/?organisation=${head.serviceProviderId}`,
      services,
      tags: head.tags ? head.tags.join(', ') : '',
      subCategories: subCategories
    }

    return data
  }

  const toDictionary = (acc, p) => {
    if (acc[p.serviceProviderId] === undefined) {
      acc[p.serviceProviderId] = [p]
    } else {
      acc[p.serviceProviderId] = [...acc[p.serviceProviderId], p]
    }
    return acc
  }

  const providersDictionary = providers
    .reduce(toDictionary, {})

  const mapped = Object.keys(providersDictionary)
    .map((id) => formatNewProvider(id, providersDictionary))

  return mapped
}

export const getServicesByDay = (dayServices) => {
  const getFullAddress = (location) => {
    return htmlEncode.htmlDecode(`${[location.street, location.street1, location.street2, location.street3, location.city]
      .filter((l) => l !== null && l.length > 0)
      .map((l) => l.trim())
      .join(', ')}. ${location.postcode.toUpperCase()}`)
  }

  const sortByOpeningTimes = (days) => {
    days.forEach(function (day) {
      day.isSelected = ko.observable(false)
      day.toggle = (e) => {
        day.isSelected(!day.isSelected())
      }
      day.serviceProviders = day.serviceProviders
        .sort((a, b) => {
          if (a.openingTime.startTime < b.openingTime.startTime) return -1
          if (a.openingTime.startTime > b.openingTime.startTime) return 1
          return 0
        })
      day.serviceProviders
        .forEach((sp) => {
          sp.name = htmlEncode.htmlDecode(sp.name)
          sp.orgUrl = `/find-help/organisation/?organisation=${sp.key}`
          sp.hasServiceInfo = hasLocationDescription(sp.serviceInfo)
          sp.hasLocationDescription = hasLocationDescription(sp.locationDescription)
          sp.fullAddress = getFullAddress(sp.address)
          sp.viewMapsUrl = `https://www.google.co.uk/maps/place/${sp.address.postcode}`
          sp.hasTelephone = sp.address.telephone !== null && sp.address.telephone.length > 0
          sp.hasTags = sp.tags.length > 0
          sp.isNotVisible = ko.observable(false)
        })
    })
    return days
  }

  function sortDaysFromToday (days) {
    // api days: monday == 0!
    var today = new Date().getDay() - 1
    var past = days.slice(0, today)
    var todayToTail = days.slice(today)
    return todayToTail.concat(past)
  }

  return sortByOpeningTimes(sortDaysFromToday(dayServices))
}
<commit_msg>shows friendly message if no services on a given day<commit_after>const apiRoutes = require('../../../api')
const browser = require('../../../browser')
const querystring = require('../../../get-url-parameter')

const ko = require('knockout')
const htmlEncode = require('htmlencode')
const marked = require('marked')
marked.setOptions({ sanitize: true })

export const buildFindHelpUrl = (locationResult, range = querystring.parameter('range')) => {
  const re = new RegExp(/find-help\/(.*)\//)
  const category = browser.location().pathname.match(re)[1]
  return apiRoutes.servicesByCategory +
    category + '/' +
    locationResult.latitude + '/' +
    locationResult.longitude +
    '?range=' + range
}

export const getSubCategories = (providers) => {
  const toJustSubCats = (accumulator, provider) => [...accumulator, ...provider.subCategories]
  const toUnique = (acc, subcat) => {
    const match = acc.find((sc) => sc.id === subcat.id)
    const result = match === undefined
      ? [...acc, subcat]
      : acc
    return result
  }

  return providers
    .reduce(toJustSubCats, [])
    .reduce(toUnique, [])
    .sort((a, b) => {
      if (a.name < b.name) return -1
      if (a.name > b.name) return 1
      return 0
    })
}

const hasLocationDescription = (description) => {
  return description !== null && description !== undefined && description.length > 0
}

export const getProvidersForListing = (providers) => {
  const groupOpeningTimes = (ungrouped) => {
    const toDictionary = (acc, curr) => {
      if (acc[curr.day] === undefined) {
        acc[curr.day] = [curr.startTime + '-' + curr.endTime]
      } else {
        acc[curr.day] = [...acc[curr.day], curr.startTime + '-' + curr.endTime]
      }
      return acc
    }

    const toDataStructure = (day) => {
      return {
        day: day,
        openingTimes: groupedByDay[day]
      }
    }

    const groupedByDay = ungrouped
      .reduce(toDictionary, {})

    return Object.keys(groupedByDay)
      .map(toDataStructure)
  }

  const extractService = (provider) => {
    const getFullAddress = (location) => {
      return htmlEncode.htmlDecode(`${[location.streetLine1, location.streetLine2, location.streetLine3, location.streetLine4, location.city]
        .filter((l) => l !== null && l.length > 0)
        .map((l) => l.trim())
        .join(', ')}. ${location.postcode.toUpperCase()}`)
    }

    provider.location.locationDescription = provider.locationDescription
    return {
      info: marked(htmlEncode.htmlDecode(provider.info)),
      location: provider.location,
      hasLocationDescription: hasLocationDescription(provider.locationDescription),
      locationDescription: provider.locationDescription,
      fullAddress: getFullAddress(provider.location),
      viewMapsUrl: `https://www.google.co.uk/maps/place/${provider.location.postcode}`,
      hasTelephone: provider.telephone !== null,
      telephone: provider.telephone,
      days: groupOpeningTimes(provider.openingTimes),
      isOpen247: provider.isOpen247,
      isTelephoneService: provider.isTelephoneService,
      isAppointmentOnly: provider.isAppointmentOnly,
      subCategoryIds: provider.subCategories
        .map((sc) => sc.id)
        .join(' '),
      servicesAvailable: provider.subCategories
        .map((sc) => sc.name)
        .join(', ')
    }
  }

  const formatNewProvider = (id, providersDictionary) => {
    const services = providersDictionary[id]
      .map((p) => extractService(p))
    const subCategories = providersDictionary[id]
      .reduce((acc, currProvider) => {
        return [...acc, ...currProvider.subCategories]
      }, [])

    const [head, ...tail] = providersDictionary[id] // eslint-disable-line

    const data = {
      providerId: head.serviceProviderId,
      providerName: htmlEncode.htmlDecode(head.serviceProviderName),
      providerPageUrl: `/find-help/organisation/?organisation=${head.serviceProviderId}`,
      services,
      tags: head.tags ? head.tags.join(', ') : '',
      subCategories: subCategories
    }

    return data
  }

  const toDictionary = (acc, p) => {
    if (acc[p.serviceProviderId] === undefined) {
      acc[p.serviceProviderId] = [p]
    } else {
      acc[p.serviceProviderId] = [...acc[p.serviceProviderId], p]
    }
    return acc
  }

  const providersDictionary = providers
    .reduce(toDictionary, {})

  const mapped = Object.keys(providersDictionary)
    .map((id) => formatNewProvider(id, providersDictionary))

  return mapped
}

export const getServicesByDay = (dayServices) => {
  const getFullAddress = (location) => {
    return htmlEncode.htmlDecode(`${[location.street, location.street1, location.street2, location.street3, location.city]
      .filter((l) => l !== null && l.length > 0)
      .map((l) => l.trim())
      .join(', ')}. ${location.postcode.toUpperCase()}`)
  }

  const sortByOpeningTimes = (days) => {
    days.forEach(function (day) {
      day.isSelected = ko.observable(false)
      day.toggle = (e) => {
        day.isSelected(!day.isSelected())
      }
      day.serviceProviders = day.serviceProviders
        .sort((a, b) => {
          if (a.openingTime.startTime < b.openingTime.startTime) return -1
          if (a.openingTime.startTime > b.openingTime.startTime) return 1
          return 0
        })
      day.serviceProviders
        .forEach((sp) => {
          sp.name = htmlEncode.htmlDecode(sp.name)
          sp.orgUrl = `/find-help/organisation/?organisation=${sp.key}`
          sp.hasServiceInfo = hasLocationDescription(sp.serviceInfo)
          sp.hasLocationDescription = hasLocationDescription(sp.locationDescription)
          sp.fullAddress = getFullAddress(sp.address)
          sp.viewMapsUrl = `https://www.google.co.uk/maps/place/${sp.address.postcode}`
          sp.hasTelephone = sp.address.telephone !== null && sp.address.telephone.length > 0
          sp.hasTags = sp.tags.length > 0
          sp.isNotVisible = ko.observable(false)
        })
      day.hasServices = ko.computed(() => {
        return day.serviceProviders.filter(sp => !sp.isNotVisible()).length > 0
      }, day)
    })
    return days
  }

  function sortDaysFromToday (days) {
    // api days: monday == 0!
    var today = new Date().getDay() - 1
    var past = days.slice(0, today)
    var todayToTail = days.slice(today)
    return todayToTail.concat(past)
  }

  return sortByOpeningTimes(sortDaysFromToday(dayServices))
}
<|endoftext|>