<commit_before>/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* map_window.js contains setup information for the
 * map tab.
 */

// library includes
Titanium.include('lib.js');
Titanium.include('skin.js');

var win,
    mapView,
    createTitleBar,
    createMapView,
    mapService = {},
    mapPoints = [],
    loadPointDetail,
    rawAnnotations = [],
    loadingIndicator;

win = Titanium.UI.currentWindow;

loadPointDetail = function (point) {
    var pointDetailWindow, bar, animation, details = [], detailTable;

    pointDetailWindow = Titanium.UI.createWindow({
        title : point.title
    });

    detailTable = Titanium.UI.createTableView();
    if (point.abbreviation) {
        detailTable.appendRow(Titanium.UI.createTableViewRow({title: point.abbreviation}));
    }
    pointDetailWindow.add(detailTable);

    pointDetailWindow.open({
        modal:true,
        modalTransitionStyle: Ti.UI.iPhone.MODAL_TRANSITION_STYLE_FLIP_HORIZONTAL,
        modalStyle: Ti.UI.iPhone.MODAL_PRESENTATION_FORMSHEET
    });

};

createTitleBar = function () {
    var bar, title, homeButton, searchField;

    // create the view container for the title bar
    bar = Titanium.UI.createView({
        backgroundColor: UPM.TITLEBAR_BACKGROUND_COLOR,
        top: 0,
        height: UPM.TITLEBAR_HEIGHT
    });
    win.add(bar);
    searchField = Titanium.UI.createSearchBar({
        backgroundColor : UPM.TITLEBAR_BACKGROUND_COLOR,
        backgroundGraident : {
            type : 'linear',
            startPoint : 0,
            endPoint : UPM.TITLEBAR_HEIGHT,
            colors : ["#000","#000"]
        },
        barColor:UPM.TITLEBAR_BACKGROUND_COLOR,
        height: UPM.TITLEBAR_HEIGHT,
        top:0,
        left:38
    });
    bar.add(searchField);
    searchField.addEventListener('change', function(e){
        Ti.API.info(e.source.value);
        mapService.search(e.source.value);
    });

    // add a navigation button to allow users to return to the home screen
    homeButton = Titanium.UI.createImageView({
        image: "icons/tab-home.png",
        height: 18,
        width: 18,
        left: 10
    });
    bar.add(homeButton);

    // add an event listener for the home button
    homeButton.addEventListener('click', function (e) {
        Ti.App.fireEvent(
            'showWindow',
            {
                oldWindow: 'settings',
                newWindow: 'home'
            }
        );
    });

};

createMapView = function () {
    var annotations, buttonBar;

    // wire up some sample annotations
    // TODO: we need real data here, as well as making some changes so that
    // this code runs successfully on Android
    annotations = [
       Titanium.Map.createAnnotation({
           latitude:47.661009,
           longitude:-122.312894,
           title:"UW Bookstore",
           subtitle:'Books and t-shirts',
           pincolor:Titanium.Map.ANNOTATION_PURPLE
       }),
       Titanium.Map.createAnnotation({
           latitude:47.653233,
           longitude:-122.305856,
           title:"CSE Department",
           subtitle:'Paul G. Allen Center',
           pincolor:Titanium.Map.ANNOTATION_GREEN
       })
   ];

   // create the map view
   mapView = Titanium.Map.createView({
       top: UPM.TITLEBAR_HEIGHT,
       mapType: Titanium.Map.STANDARD_TYPE,
       region:{
           latitude:UPM.DEFAULT_LATITUDE,
           longitude:UPM.DEFAULT_LONGITUDE,
           latitudeDelta:0.01,
           longitudeDelta:0.01
       },
       regionFit:true,
       userLocation:true,
       annotations:annotations
   });
   win.add(mapView);

   // create controls for zoomin / zoomout
   buttonBar = Titanium.UI.createButtonBar({
       labels:['+', '-'],
       backgroundColor:'#336699',
       style:Titanium.UI.iPhone.SystemButtonStyle.BAR,
       top: Ti.Platform.displayCaps.platformHeight - 130,
       width: 100,
       height: 25
   });
   mapView.add(buttonBar);

   // add event listeners for the zoom buttons
   buttonBar.addEventListener('click', function (e) {
       if (e.index == 0) {
           mapView.zoom(1);
       } else {
           mapView.zoom(-1);
       }
   });

};

mapService.search = function (query, opts) {
    var searchBusy;

    //If a search isn't already executing
    if(!searchBusy) {
        searchBusy = true;
        mapPoints = [];
        for (var i=0, iLength = rawAnnotations.length; i<iLength; i++) {
            if (rawAnnotations[i].title.search(query) != -1) {
                mapPoints.push(Titanium.Map.createAnnotation(rawAnnotations[i]));
            }
        }
        mapView.annotations = mapPoints;
    }
    searchBusy = false;
};
mapService.updateMapPoints = function (filters) {
    //Default returns all points for an institution.
    //Can be filtered by campus, admin-defined categories
    if (!mapService.pointCache) {
        request = Titanium.Network.createHTTPClient ({
            connectionType : 'GET',
            location : UPM.MAP_SERVICE_URL,
            onload : mapService.newPointsLoaded,
            onerror : function (e) {
                Ti.API.info("Error with map service" + this.responseText);
            }
        });
        request.open("GET",'http://localhost:8080/uPortal/services/map-test-data.json');
        request.send();
    }
};
mapService.newPointsLoaded = function (e) {
    var response = JSON.parse(e.source.responseText),
        mapAnnotation;
    for (var i = 0, iLength = response.buildings.length; i < iLength; i++) {
        response.buildings[i].title = response.buildings[i].name;
        response.buildings[i].leftView = Titanium.UI.createImageView({
            // image : response.buildings[i].img
            image : 'http://localhost:8080/uPortal/media/skins/icons/google.png', //temporary since images in feed are no good.
            width : 32,
            height :32
        });
        rawAnnotations.push(response.buildings[i]);
        mapAnnotation = Titanium.Map.createAnnotation(response.buildings[i]);
        mapAnnotation.addEventListener("click",function(e){
            Ti.API.info("clicked a point" + e.source);
            loadPointDetail(e.source);
        });
        mapPoints.push(mapAnnotation);

        // Ti.API.info("Building is: " + response.buildings[i].abbreviation);

    }
    mapView.annotations = mapPoints;
};

createTitleBar();
createMapView();
mapService.updateMapPoints();
<commit_msg>UMOBILE-2 Updating map search to ignore case<commit_after>/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* map_window.js contains setup information for the
 * map tab.
 */

// library includes
Titanium.include('lib.js');
Titanium.include('skin.js');

var win,
    mapView,
    createTitleBar,
    createMapView,
    mapService = {},
    mapPoints = [],
    loadPointDetail,
    rawAnnotations = [],
    loadingIndicator;

win = Titanium.UI.currentWindow;

loadPointDetail = function (point) {
    var pointDetailWindow, bar, animation, details = [], detailTable;

    pointDetailWindow = Titanium.UI.createWindow({
        title : point.title
    });

    detailTable = Titanium.UI.createTableView();
    if (point.abbreviation) {
        detailTable.appendRow(Titanium.UI.createTableViewRow({title: point.abbreviation}));
    }
    pointDetailWindow.add(detailTable);

    pointDetailWindow.open({
        modal:true,
        modalTransitionStyle: Ti.UI.iPhone.MODAL_TRANSITION_STYLE_FLIP_HORIZONTAL,
        modalStyle: Ti.UI.iPhone.MODAL_PRESENTATION_FORMSHEET
    });

};

createTitleBar = function () {
    var bar, title, homeButton, searchField;

    // create the view container for the title bar
    bar = Titanium.UI.createView({
        backgroundColor: UPM.TITLEBAR_BACKGROUND_COLOR,
        top: 0,
        height: UPM.TITLEBAR_HEIGHT
    });
    win.add(bar);
    searchField = Titanium.UI.createSearchBar({
        backgroundColor : UPM.TITLEBAR_BACKGROUND_COLOR,
        backgroundGraident : {
            type : 'linear',
            startPoint : 0,
            endPoint : UPM.TITLEBAR_HEIGHT,
            colors : ["#000","#000"]
        },
        barColor:UPM.TITLEBAR_BACKGROUND_COLOR,
        height: UPM.TITLEBAR_HEIGHT,
        top:0,
        left:38
    });
    bar.add(searchField);
    searchField.addEventListener('change', function(e){
        Ti.API.info(e.source.value);
        mapService.search(e.source.value);
    });

    // add a navigation button to allow users to return to the home screen
    homeButton = Titanium.UI.createImageView({
        image: "icons/tab-home.png",
        height: 18,
        width: 18,
        left: 10
    });
    bar.add(homeButton);

    // add an event listener for the home button
    homeButton.addEventListener('click', function (e) {
        Ti.App.fireEvent(
            'showWindow',
            {
                oldWindow: 'settings',
                newWindow: 'home'
            }
        );
    });

};

createMapView = function () {
    var annotations, buttonBar;

    // wire up some sample annotations
    // TODO: we need real data here, as well as making some changes so that
    // this code runs successfully on Android
    annotations = [
       Titanium.Map.createAnnotation({
           latitude:47.661009,
           longitude:-122.312894,
           title:"UW Bookstore",
           subtitle:'Books and t-shirts',
           pincolor:Titanium.Map.ANNOTATION_PURPLE
       }),
       Titanium.Map.createAnnotation({
           latitude:47.653233,
           longitude:-122.305856,
           title:"CSE Department",
           subtitle:'Paul G. Allen Center',
           pincolor:Titanium.Map.ANNOTATION_GREEN
       })
   ];

   // create the map view
   mapView = Titanium.Map.createView({
       top: UPM.TITLEBAR_HEIGHT,
       mapType: Titanium.Map.STANDARD_TYPE,
       region:{
           latitude:UPM.DEFAULT_LATITUDE,
           longitude:UPM.DEFAULT_LONGITUDE,
           latitudeDelta:0.01,
           longitudeDelta:0.01
       },
       regionFit:true,
       userLocation:true,
       annotations:annotations
   });
   win.add(mapView);

   // create controls for zoomin / zoomout
   buttonBar = Titanium.UI.createButtonBar({
       labels:['+', '-'],
       backgroundColor:'#336699',
       style:Titanium.UI.iPhone.SystemButtonStyle.BAR,
       top: Ti.Platform.displayCaps.platformHeight - 130,
       width: 100,
       height: 25
   });
   mapView.add(buttonBar);

   // add event listeners for the zoom buttons
   buttonBar.addEventListener('click', function (e) {
       if (e.index == 0) {
           mapView.zoom(1);
       } else {
           mapView.zoom(-1);
       }
   });

};

mapService.search = function (query, opts) {
    var searchBusy;
    query = query.toLowerCase();

    //If a search isn't already executing
    if(!searchBusy) {
        searchBusy = true;
        mapPoints = [];
        for (var i=0, iLength = rawAnnotations.length; i<iLength; i++) {
            if (rawAnnotations[i].title.toLowerCase().search(query) != -1) {
                mapPoints.push(Titanium.Map.createAnnotation(rawAnnotations[i]));
            }
        }
        mapView.annotations = mapPoints;
    }
    searchBusy = false;
};
mapService.updateMapPoints = function (filters) {
    //Default returns all points for an institution.
    //Can be filtered by campus, admin-defined categories
    if (!mapService.pointCache) {
        request = Titanium.Network.createHTTPClient ({
            connectionType : 'GET',
            onload : mapService.newPointsLoaded,
            onerror : function (e) {
                Ti.API.info("Error with map service" + this.responseText);
            }
        });
        request.open("GET", UPM.MAP_SERVICE_URL);
        request.send();
    }
};
mapService.newPointsLoaded = function (e) {
    var response = JSON.parse(e.source.responseText),
        mapAnnotation;
    for (var i = 0, iLength = response.buildings.length; i < iLength; i++) {
        response.buildings[i].title = response.buildings[i].name;
        response.buildings[i].leftView = Titanium.UI.createImageView({
            // image : response.buildings[i].img
            image : 'http://localhost:8080/uPortal/media/skins/icons/google.png', //temporary since images in feed are no good.
            width : 32,
            height :32
        });
        rawAnnotations.push(response.buildings[i]);
        mapAnnotation = Titanium.Map.createAnnotation(response.buildings[i]);
        mapAnnotation.addEventListener("click",function(e){
            Ti.API.info("clicked a point" + e.source);
            loadPointDetail(e.source);
        });
        mapPoints.push(mapAnnotation);

        // Ti.API.info("Building is: " + response.buildings[i].abbreviation);

    }
    mapView.annotations = mapPoints;
};

createTitleBar();
createMapView();
mapService.updateMapPoints();
<|endoftext|>


<commit_before>jQuery.sap.require("oui5lib.configuration");
jQuery.sap.require("oui5lib.request");

jQuery.sap.declare("oui5lib.currentuser");

(function () {
    "use strict";

    /** @namespace oui5lib.currentuser */
    var user = oui5lib.namespace("currentuser"),
    _name = null,
    _userId = null,
    _token = null,
    _userRoles = [],
    _permissionsMap = null;

    /**
     * Get the user's name
     * @function getName
     * @memberof oui5lib.currentuser
     * @returns {string} the user's firstname lastname)
     */
    function getName() {
        return _name;
    }

    /**
     * Get the user's uniquename from the currentProfile.
     * @function getUniquename
     * @memberof oui5lib.currentuser
     * @returns {string} the user's uniquename
     */
    function getUserId() {
        return _userId;
    }

    function hasPermissionForView(viewName) {
        if (typeof _permissionsMap.views[viewName] !== "undefined") {
            var viewRoles = _permissionsMap.views[viewName].roles;
            return hasPermissions(viewRoles);
        }
        return true;
    }

    /**
     * Test, if the user has permissions.
     * @function hasPermissions
     * @memberof oui5lib.currentuser
     * @param {array} userRoles The required user role names.
     * @returns {boolean}
     */
    function hasPermissions(authorizedRoles) {
        if (typeof authorizedRoles === "undefined" ||
            !(authorizedRoles instanceof Array)) {
            return false;
        }

        var authorized = false,
            i, s;

        for (i = 0, s = authorizedRoles.length; i < s; i++) {
            if (hasRole(authorizedRoles[i])) {
                authorized = true;
                break;
            }
        }
        return authorized;
    }

    /**
     * Test, if the user has the specified user role.
     * @function hasUserRole
     * @memberof oui5lib.currentuser
     * @param {string} role The role name.
     * @returns {boolean}
     */
    function hasRole(role) {
        return _userRoles.indexOf(role) > -1;
    }

    /**
     * Initialize the current user object.
     */
    function init() {
        var userProfileUrl = oui5lib.configuration.getUserProfileUrl();
        if (userProfileUrl !== null) {
            requestUserProfile(userProfileUrl);
        }

        oui5lib.request.loadJson("permissions.json",
                                 permissionsMapRequestSucceeded,
                                 {}, false);
    }

    /**
     * Requests user authorization and profile.
     */
    function requestUserProfile(userProfileUrl) {
        oui5lib.request.loadJson(userProfileUrl,
                                 userProfileRequestSucceeded,
                                 {}, false);
    }

    function userProfileRequestSucceeded(userProfile) {
        if (userProfile !== null) {
            _name = userProfile.firstname + " " + userProfile.lastname;
            _userId = userProfile.userId;
            _token = userProfile.token;

            if (userProfile.roles instanceof Array) {
                _userRoles = userProfile.roles;
            }
        }
    }

    function permissionsMapRequestSucceeded(permissionsMap) {
        _permissionsMap = permissionsMap;
    }

    user.init = init;

    user.getName = getName;
    user.getUserId = getUserId;

    user.hasRole = hasRole;
    user.hasPermissionForView = hasPermissionForView;
}());
<commit_msg>currentuser improved<commit_after>jQuery.sap.require("oui5lib.configuration");
jQuery.sap.require("oui5lib.request");

jQuery.sap.declare("oui5lib.currentuser");

(function () {
    "use strict";

    /** @namespace oui5lib.currentuser */
    var user = oui5lib.namespace("currentuser"),
    _name = null,
    _userId = null,
    _token = null,
    _userRoles = [],
    _permissionsMap = null;

    /**
     * Get the user's name
     * @function getName
     * @memberof oui5lib.currentuser
     * @returns {string} the user's firstname lastname)
     */
    function getName() {
        return _name;
    }

    /**
     * Get the user's uniquename from the currentProfile.
     * @function getUniquename
     * @memberof oui5lib.currentuser
     * @returns {string} the user's uniquename
     */
    function getUserId() {
        return _userId;
    }

    function hasPermissionForView(viewName) {
        if (_permissionsMap === null) {
            return false;
        }
        if (typeof _permissionsMap.views[viewName] !== "undefined") {
            var viewRoles = _permissionsMap.views[viewName].roles;
            return hasPermissions(viewRoles);
        }
        return true;
    }

    /**
     * Test, if the user has permissions.
     * @function hasPermissions
     * @memberof oui5lib.currentuser
     * @param {array} userRoles The required user role names.
     * @returns {boolean}
     */
    function hasPermissions(authorizedRoles) {
        if (typeof authorizedRoles === "undefined" ||
            !(authorizedRoles instanceof Array)) {
            return false;
        }

        var authorized = false,
            i, s;

        for (i = 0, s = authorizedRoles.length; i < s; i++) {
            if (hasRole(authorizedRoles[i])) {
                authorized = true;
                break;
            }
        }
        return authorized;
    }

    /**
     * Test, if the user has the specified user role.
     * @function hasUserRole
     * @memberof oui5lib.currentuser
     * @param {string} role The role name.
     * @returns {boolean}
     */
    function hasRole(role) {
        return _userRoles.indexOf(role) > -1;
    }

    /**
     * Initialize the current user object.
     */
    function init() {
        var userProfileUrl = oui5lib.configuration.getUserProfileUrl();
        if (userProfileUrl !== null) {
            requestUserProfile(userProfileUrl);
        }

        oui5lib.request.loadJson("permissions.json",
                                 permissionsMapRequestSucceeded,
                                 {}, false);
    }

    /**
     * Requests user authorization and profile.
     */
    function requestUserProfile(userProfileUrl) {
        oui5lib.request.loadJson(userProfileUrl,
                                 userProfileRequestSucceeded,
                                 {}, false);
    }

    function userProfileRequestSucceeded(userProfile) {
        if (userProfile !== null) {
            _name = userProfile.firstname + " " + userProfile.lastname;
            _userId = userProfile.userId;
            _token = userProfile.token;

            if (userProfile.roles instanceof Array) {
                _userRoles = userProfile.roles;
            }
        }
    }

    function permissionsMapRequestSucceeded(permissionsMap) {
        _permissionsMap = permissionsMap;
    }

    user.init = init;

    user.getName = getName;
    user.getUserId = getUserId;

    user.hasRole = hasRole;
    user.hasPermissionForView = hasPermissionForView;
}());
<|endoftext|>


<commit_before>import h from 'react-hyperscript'

import Collapsible from 'reusableComponents/collapsible'
import {
  BackEnd,
  Code,
  FrontEnd,
  Movie,
  Music,
  Pencil,
  People,
  SupaHappy,
  ThumbUp,
  TV
} from 'svg'
import settings from 'settings'

const { greyDarken } = settings

const li = text => h('li', {}, text)

export const clFrontEnd = h(Collapsible,
  {
    titleIcon: FrontEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Front-end',
    popOut: true
  },
  [
    h('ul', [
      li('HTML5 / CSS3'),
      li('Jade (I mean Pug 🐶...)'),
      li('SCSS / Less / Stylus'),
      li('PostCSS')
    ]),
    h('p', [
      'To organize my stylesheets, I try to follow the ',
      h('a.u-linkSweep.u-highlight',
        { href: 'https://smacss.com/', target: '_blank' },
        'SMACSS '
      ),
      'guidelines and the ',
      h(
        'a.u-linkSweep.u-highlight',
        { href: 'https://suitcss.github.io/', target: '_blank' },
        'SUIT CSS '
      ),
      'naming conventions.'
    ]),
    h('p', [
      'On the JS side, I follow the ',
      h('a.u-linkSweep.u-highlight',
        { href: 'https://standardjs.com/', target: '_blank' },
        'Standard JS '
      ),
      'rules.'
    ]),
    h(
      Collapsible,
      {
        titleIcon: Code,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'JS'
      },
      h('ul', [
        li('ES6'),
        li('TypeScript'),
        li('Flux-like architectures')
      ])
    ),
    h(Collapsible,
      {
        titleIcon: Pencil,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Design'
      },
      h('ul', [li('Figma'), li('Sketch'), li('Affinity Designer')])
    )
  ]
)

export const clBackEnd = h(Collapsible,
  {
    titleIcon: BackEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Back-end',
    popOut: true
  },
  [h('ul', [li('Node.js / Express'), li('MongoDB')])]
)

export const clTools = h(Collapsible,
  {
    titleIcon: ThumbUp,
    iconColor: greyDarken,
    titleIconSize: 30,
    title: 'Tools I like',
    popOut: true
  },
  [
    h('ul', [
      li('iTerm2'),
      li('npm / yarn'),
      li('Webpack'),
      li('CSS Modules'),
      li('ESLint / TSLint / Stylelint'),
      li('Homebrew 🍺')
    ]),
    h('p', [
      'And if you must know, I work on a ',
      h('span.u-highlight', 'MacBook Pro '),
      'using ',
      h('span.u-highlight', 'Visual Studio Code '),
      'as my code editor.'
    ])
  ]
)

export const clMusic = h(Collapsible,
  {
    titleIcon: Music,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Music',
    popOut: true
  },
  [
    h('p',
      `Music is so many things, it can soothe you, move you, make you move, annoy you or even make you fall asleep, it's just fundamental :)`
    ),
    h(Collapsible, { iconColor: greyDarken, title: 'Rap' }, [
      h('p', 'Of course this is not an exhaustive list :'),
      h('ul', [
        li('Dave East'),
        li('TDE'),
        li(`Chance the Rapper (he's like Kanye West before Kanye became a Kardashian)`),
        li('Joey Bada$$'),
        li('Young Thug'),
        li(`ASAP Mob (not all of 'em...)`),
        li(
          `Cam'ron, The Wu-Tang Clan, The Notorious B.I.G, Kurupt...(never forget what time it is ;)`
        )
      ])
    ]),
    h(Collapsible, { iconColor: greyDarken, title: 'B-Side' }, [
      h('p',
        'All right, now get ready for the dummy mix, no rules, just me, my taste and no filter :'
      ),
      h('ul', [
        li('Jhené Aiko'),
        li('Paramore'),
        li('Frank Ocean'),
        li('Mélat'),
        li(`Blink-182 (didn't even listen to them as a teen, but man they're good)`),
        li('A-Trak'),
        li('...')
      ])
    ])
  ]
)

export const clTVMovies = h(Collapsible,
  {
    titleIcon: TV,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Netflix & ...',
    popOut: true
  },
  [
    h('p', 'Another non exhaustive list :'),
    h('ul', [
      li('Stranger Things'),
      li('Black Mirror'),
      li('Daredevil'),
      li('Mr. Robot'),
      li('Narcos'),
      li('GoT'),
      li('Orange is the new black'),
      li('...')
    ]),
    h(Collapsible,
      {
        titleIcon: Movie,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Movies'
      },
      [
        h('p',
          `Maybe not my favorites of all time, but the ones that pop into my head as I'm writing this.`
        ),
        h('ul', [
          li('Pitch Perfect (nerd alert!)'),
          li('The Nice Guys'),
          li('End of watch'),
          li('50/50'),
          li(`Kingsman`),
          li('22 Jump Street'),
          li('...')
        ])
      ]
    )
  ]
)

export const clPeople = h(Collapsible,
  {
    titleIcon: People,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Following',
    popOut: true
  },
  [
    h('p', 'Some devs I follow, look up to, and/or simply like :'),
    h('ul', [
      h('li', [
        h('a.u-linkSweep',
          { href: 'http://bit.ly/1KcNPaY', target: '_blank' },
          'Mattias Petter Johansson'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'http://sidebar.io/', target: '_blank' },
          'Sacha Greif'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://una.im/', target: '_blank' },
          'Una Kravets'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://bitsofco.de/', target: '_blank' },
          'Ire Aderinokun'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://pawelgrzybek.com/', target: '_blank' },
          'Pawel Grzybek'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://medium.com/@_ericelliott/latest', target: '_blank' },
          'Eric Elliott'
        )
      ])
    ])
  ]
)

export const clMisc = h(Collapsible,
  {
    titleIcon: SupaHappy,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Misc',
    popOut: true
  },
  [
    h('p', [
      'And of course, I like to have my ',
      h('span.u-highlight', '5 vegetables '),
      'a day (I mean, it feels good when I do...which is like once a month).'
    ]),
    h('p', [
      'And last but not least, I like people (well,',
      h('span.u-highlight', ` some of 'em, `),
      `sometimes..., my heart's not that big 😛), I mean music, tv series, your opinion about what's happening on the other side of the world and stuff is great...`
    ]),
    h('p',
      `But what's greater is when you get to share (and disagree with) all that with someone else, otherwise, what's the point, right?`
    )
  ]
)
<commit_msg>* update content<commit_after>import h from 'react-hyperscript'

import Collapsible from 'reusableComponents/collapsible'
import {
  BackEnd,
  Code,
  FrontEnd,
  Movie,
  Music,
  Pencil,
  People,
  SupaHappy,
  ThumbUp,
  TV
} from 'svg'
import settings from 'settings'

const { greyDarken } = settings

const li = text => h('li', {}, text)

export const clFrontEnd = h(Collapsible,
  {
    titleIcon: FrontEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Front-end',
    popOut: true
  },
  [
    h('ul', [
      li('HTML5 / CSS3'),
      li('Jade (I mean Pug 🐶...)'),
      li('SCSS / Less / Stylus'),
      li('PostCSS')
    ]),
    h('p', [
      'To organize my stylesheets, I try to follow the ',
      h('a.u-linkSweep.u-highlight',
        { href: 'https://smacss.com/', target: '_blank' },
        'SMACSS '
      ),
      'guidelines and the ',
      h(
        'a.u-linkSweep.u-highlight',
        { href: 'https://suitcss.github.io/', target: '_blank' },
        'SUIT CSS '
      ),
      'naming conventions.'
    ]),
    h('p', [
      'On the JS side, I follow the ',
      h('a.u-linkSweep.u-highlight',
        { href: 'https://standardjs.com/', target: '_blank' },
        'Standard JS '
      ),
      'rules.'
    ]),
    h(
      Collapsible,
      {
        titleIcon: Code,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'JS'
      },
      h('ul', [
        li('ES6'),
        li('TypeScript'),
        li('Flux-like architectures')
      ])
    ),
    h(Collapsible,
      {
        titleIcon: Pencil,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Design'
      },
      h('ul', [li('Figma'), li('Sketch'), li('Affinity Designer')])
    )
  ]
)

export const clBackEnd = h(Collapsible,
  {
    titleIcon: BackEnd,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Back-end',
    popOut: true
  },
  [h('ul', [li('Node.js / Express'), li('MongoDB')])]
)

export const clTools = h(Collapsible,
  {
    titleIcon: ThumbUp,
    iconColor: greyDarken,
    titleIconSize: 30,
    title: 'Tools I like',
    popOut: true
  },
  [
    h('ul', [
      li('iTerm2'),
      li('npm / yarn'),
      li('Webpack'),
      li('CSS Modules'),
      li('ESLint / TSLint / Stylelint'),
      li('Homebrew 🍺')
    ]),
    h('p', [
      'And if you must know, I work on a ',
      h('span.u-highlight', 'MacBook Pro '),
      'using ',
      h('span.u-highlight', 'Visual Studio Code '),
      'as my code editor.'
    ])
  ]
)

export const clMusic = h(Collapsible,
  {
    titleIcon: Music,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Music',
    popOut: true
  },
  [
    h('p',
      `Music is so many things, it can soothe you, move you, make you move, annoy you or even make you fall asleep, it's just fundamental :)`
    ),
    h(Collapsible, { iconColor: greyDarken, title: 'Rap' }, [
      h('p', 'Of course this is not an exhaustive list :'),
      h('ul', [
        li('Dave East'),
        li('TDE'),
        li(`Chance the Rapper (he's like Kanye West before Kanye became a Kardashian)`),
        li('Joey Bada$$'),
        li('Young Thug'),
        li(`ASAP Mob (not all of 'em...)`),
        li(
          `Cam'ron, The Wu-Tang Clan, The Notorious B.I.G, Kurupt...(never forget what time it is ;)`
        )
      ])
    ]),
    h(Collapsible, { iconColor: greyDarken, title: 'B-Side' }, [
      h('p',
        'All right, now get ready for the dummy mix, no rules, just me, my taste and no filter :'
      ),
      h('ul', [
        li('Jhené Aiko'),
        li('Paramore'),
        li('Frank Ocean'),
        li('Mélat'),
        li(`Blink-182 (didn't even listen to them as a teen, but man they're good)`),
        li('A-Trak'),
        li('...')
      ])
    ])
  ]
)

export const clTVMovies = h(Collapsible,
  {
    titleIcon: TV,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Netflix & ...',
    popOut: true
  },
  [
    h('p', 'Another non exhaustive list :'),
    h('ul', [
      li('Stranger Things'),
      li('Black Mirror'),
      li('Daredevil'),
      li('Mr. Robot'),
      li('Narcos'),
      li('GoT'),
      li('Orange is the new black'),
      li('...')
    ]),
    h(Collapsible,
      {
        titleIcon: Movie,
        iconColor: greyDarken,
        titleIconSize: 35,
        title: 'Movies'
      },
      [
        h('p',
          `Maybe not my favorites of all time, but the ones that pop into my head as I'm writing this.`
        ),
        h('ul', [
          li('Pitch Perfect (nerd alert!)'),
          li('The Nice Guys'),
          li('End of watch'),
          li('50/50'),
          li(`Kingsman`),
          li('22 Jump Street'),
          li('...')
        ])
      ]
    )
  ]
)

export const clPeople = h(Collapsible,
  {
    titleIcon: People,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Following',
    popOut: true
  },
  [
    h('p', 'Some devs I follow, look up to, and/or simply like :'),
    h('ul', [
      h('li', [
        h('a.u-linkSweep',
          { href: 'http://bit.ly/1KcNPaY', target: '_blank' },
          'Mattias Petter Johansson'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://blog.mariusschulz.com/', target: '_blank' },
          'Marius Schulz'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'http://sidebar.io/', target: '_blank' },
          'Sacha Greif'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://bitsofco.de/', target: '_blank' },
          'Ire Aderinokun'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://pawelgrzybek.com/', target: '_blank' },
          'Pawel Grzybek'
        )
      ]),
      h('li', [
        h('a.u-linkSweep',
          { href: 'https://medium.com/@_ericelliott/latest', target: '_blank' },
          'Eric Elliott'
        )
      ])
    ])
  ]
)

export const clMisc = h(Collapsible,
  {
    titleIcon: SupaHappy,
    iconColor: greyDarken,
    titleIconSize: 35,
    title: 'Misc',
    popOut: true
  },
  [
    h('p', [
      'And of course, I like to have my ',
      h('span.u-highlight', '5 vegetables '),
      'a day (I mean, it feels good when I do...which is like once a month).'
    ]),
    h('p', [
      'And last but not least, I like people (well,',
      h('span.u-highlight', ` some of 'em, `),
      `sometimes..., my heart's not that big 😛), I mean music, tv series, your opinion about what's happening on the other side of the world and stuff is great...`
    ]),
    h('p',
      `But what's greater is when you get to share (and disagree with) all that with someone else, otherwise, what's the point, right?`
    )
  ]
)
<|endoftext|>


<commit_before>import Immutable from 'immutable'
import MJMLElementsCollection from '../../MJMLElementsCollection'
import React, { Component } from 'react'
import _ from 'lodash'
import { widthParser } from "../../helpers/mjAttribute"
import { UnknownMJMLElement } from '../../Error'

const getElementWidth = (element, siblings) => {
  const { elem } = element.props
  let { width } = element.props

  if (!width && elem && elem.attributes && elem.attributes.width) {
    width = elem.attributes.width
  }

  if (width == undefined) {
    return 600 / siblings
  }

  const { width: parsedWidth, unit } = widthParser(width)

  switch(unit) {
  case '%':
    return parsedWidth * 6 // * 600 / 100

  case 'px':
  default:
    return parsedWidth
  }
}

function createComponent(ComposedComponent, defaultAttributes) {

  class MJMLElement extends Component {

    constructor(props) {
      super(props)

      this.state = Immutable.fromJS({
        elem: _.merge({
          children: [],
          attributes: {}
        }, defaultAttributes)
      })

      this.state = this.state.mergeDeep(props)
    }

    mjAttribute(name) {
      if (this.props[name] != undefined) {
        return this.props[name]
      }

      return this.state.getIn(['elem', 'attributes']).get(name)
    }

    mjContent() {
      return _.trim(this.state.getIn(['elem', 'content'])) || React.renderToStaticMarkup(this.props.children)
    }

    mjElementName() {
      return this.state.getIn(['elem', 'tagName']).substr(3)
    }

    siblingsCount() {
      return this.hasReactChildren() ?  React.Children.count(children) : this.state.getIn(['elem', 'children']).size
    }

    childDefaultProps(id) {
      return {
        id,
        key: id,
        color: this.mjAttribute('color'),
        parentWidth: this.mjAttribute('rawPxWidth'),
        verticalAlign: this.mjAttribute('vertical-align'),
        sibling: this.siblingsCount()
      }
    }

    renderWrappedOutlookChildren() {
      let elements          = this.renderChildren()
      const wrappedElements = []
      const prefix          = `mj-${this.mjElementName()}-outlook`

      if (elements && elements.get) {
        // had to break immutable here :(
        elements = elements.toArray()
      }

      if (elements.length == 0) {
        return []
      }

      elements.forEach((element, n) => {
        const width = getElementWidth(element, elements.length)
        wrappedElements.push(React.cloneElement(element, {rawPxWidth: width}))

        if ( n < elements.length - 1 ) {
          const nextWidth = getElementWidth(elements[n+1], elements.length)

          wrappedElements.push(<div key={`outlook-${n}`}className={`${prefix}-line`} data-width={nextWidth}/>)
        }
      })

      const outlookOpenTag  = <div key="outlook-open" className={`${prefix}-open`} data-width={getElementWidth(elements[0], elements.length)} />
      const outlookCloseTag = <div key="outlook-close" className={`${prefix}-close`} />

      return [outlookOpenTag].concat(wrappedElements, [outlookCloseTag])
    }

    upgradeReactChildren(children) {
      return children.map((child, i) => {
        return React.cloneElement(child, this.childDefaultProps(i))
      })
    }

    hasReactChildren() {
      const children = this.state.getIn(['elem', 'children'])

      return !children || children.count() === 0 && React.Children.count(this.props.children) >= 1
    }

    renderChildren() {
      if (this.hasReactChildren()) {
        return this.upgradeReactChildren(React.Children.toArray(this.props.children));
      }

      const children = this.state.getIn(['elem', 'children'])
      let i = 0

      return children.map((elem) => {
        if (elem.get('tagName') && elem.get('tagName').indexOf('mj-') != -1) {
          i++

          const Element = MJMLElementsCollection[elem.get('tagName').substr(3)]

          if (!Element) {
            throw new UnknownMJMLElement(`Could not find element for : ${elem.get('tagName')}`)
          }

          const props = _.merge(this.childDefaultProps(i), {
            elem: elem.toJS(),
          })

          return React.createElement(Element, props)
        }
      })
    }

    render() {
      return (
        <ComposedComponent
          {...this.props}
          mjAttribute={::this.mjAttribute}
          mjContent={::this.mjContent}
          mjElementName={::this.mjElementName}
          renderChildren={::this.renderChildren}
          renderWrappedOutlookChildren={::this.renderWrappedOutlookChildren} />
      )
    }

  }

  return MJMLElement

}

export default (defaultAttributes) => {
  if (typeof defaultAttributes == 'function') {
    return createComponent(defaultAttributes)
  }

  return ComposedComponent => createComponent(ComposedComponent, defaultAttributes)
}
<commit_msg>Fix custom component siblings count<commit_after>import Immutable from 'immutable'
import MJMLElementsCollection from '../../MJMLElementsCollection'
import React, { Component } from 'react'
import _ from 'lodash'
import { widthParser } from "../../helpers/mjAttribute"
import { UnknownMJMLElement } from '../../Error'

const getElementWidth = (element, siblings) => {
  const { elem } = element.props
  let { width } = element.props

  if (!width && elem && elem.attributes && elem.attributes.width) {
    width = elem.attributes.width
  }

  if (width == undefined) {
    return 600 / siblings
  }

  const { width: parsedWidth, unit } = widthParser(width)

  switch(unit) {
  case '%':
    return parsedWidth * 6 // * 600 / 100

  case 'px':
  default:
    return parsedWidth
  }
}

function createComponent(ComposedComponent, defaultAttributes) {

  class MJMLElement extends Component {

    constructor(props) {
      super(props)

      this.state = Immutable.fromJS({
        elem: _.merge({
          children: [],
          attributes: {}
        }, defaultAttributes)
      })

      this.state = this.state.mergeDeep(props)
    }

    mjAttribute(name) {
      if (this.props[name] != undefined) {
        return this.props[name]
      }

      return this.state.getIn(['elem', 'attributes']).get(name)
    }

    mjContent() {
      return _.trim(this.state.getIn(['elem', 'content'])) || React.renderToStaticMarkup(this.props.children)
    }

    mjElementName() {
      return this.state.getIn(['elem', 'tagName']).substr(3)
    }

    siblingsCount() {
      const children = this.state.getIn(['elem', 'children'])

      return this.hasReactChildren() ?  React.Children.count(children) : this.state.getIn(['elem', 'children']).size
    }

    childDefaultProps(id) {
      return {
        id,
        key: id,
        color: this.mjAttribute('color'),
        parentWidth: this.mjAttribute('rawPxWidth'),
        verticalAlign: this.mjAttribute('vertical-align'),
        sibling: this.siblingsCount()
      }
    }

    renderWrappedOutlookChildren() {
      let elements          = this.renderChildren()
      const wrappedElements = []
      const prefix          = `mj-${this.mjElementName()}-outlook`

      if (elements && elements.get) {
        // had to break immutable here :(
        elements = elements.toArray()
      }

      if (elements.length == 0) {
        return []
      }

      elements.forEach((element, n) => {
        const width = getElementWidth(element, elements.length)
        wrappedElements.push(React.cloneElement(element, {rawPxWidth: width}))

        if ( n < elements.length - 1 ) {
          const nextWidth = getElementWidth(elements[n+1], elements.length)

          wrappedElements.push(<div key={`outlook-${n}`}className={`${prefix}-line`} data-width={nextWidth}/>)
        }
      })

      const outlookOpenTag  = <div key="outlook-open" className={`${prefix}-open`} data-width={getElementWidth(elements[0], elements.length)} />
      const outlookCloseTag = <div key="outlook-close" className={`${prefix}-close`} />

      return [outlookOpenTag].concat(wrappedElements, [outlookCloseTag])
    }

    upgradeReactChildren(children) {
      return children.map((child, i) => {
        return React.cloneElement(child, this.childDefaultProps(i))
      })
    }

    hasReactChildren() {
      const children = this.state.getIn(['elem', 'children'])

      return !children || children.count() === 0 && React.Children.count(this.props.children) >= 1
    }

    renderChildren() {
      if (this.hasReactChildren()) {
        return this.upgradeReactChildren(React.Children.toArray(this.props.children));
      }

      const children = this.state.getIn(['elem', 'children'])
      let i = 0

      return children.map((elem) => {
        if (elem.get('tagName') && elem.get('tagName').indexOf('mj-') != -1) {
          i++

          const Element = MJMLElementsCollection[elem.get('tagName').substr(3)]

          if (!Element) {
            throw new UnknownMJMLElement(`Could not find element for : ${elem.get('tagName')}`)
          }

          const props = _.merge(this.childDefaultProps(i), {
            elem: elem.toJS(),
          })

          return React.createElement(Element, props)
        }
      })
    }

    render() {
      return (
        <ComposedComponent
          {...this.props}
          mjAttribute={::this.mjAttribute}
          mjContent={::this.mjContent}
          mjElementName={::this.mjElementName}
          renderChildren={::this.renderChildren}
          renderWrappedOutlookChildren={::this.renderWrappedOutlookChildren} />
      )
    }

  }

  return MJMLElement

}

export default (defaultAttributes) => {
  if (typeof defaultAttributes == 'function') {
    return createComponent(defaultAttributes)
  }

  return ComposedComponent => createComponent(ComposedComponent, defaultAttributes)
}
<|endoftext|>


<commit_before>//git commit -m"feat: 新增功能"
//规范团队commit规范，参考commitlint-angular https://www.npmjs.com/package/@commitlint/config-angular
module.exports = {
  extends: ['@commitlint/config-angular'],
  rules: {
    'type-enum': [2, 'always', ["my-type",
      "feat", "fix", "docs", "style", "refactor", "test", "chore", "revert"
    ]],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never']
  }
};

//[build, ci, docs, feat, fix, perf, refactor, revert, style, test]

<commit_msg>fix: add commit lint<commit_after>//git commit -m"feat: 新增功能"
//规范团队commit规范，参考commitlint-angular https://www.npmjs.com/package/@commitlint/config-angular
module.exports = {
  extends: ['@commitlint/config-angular'],
  rules: {
    'type-enum': [2, 'always', [
      "feat", "fix", "docs", "style", "refactor", "test", "chore", "revert"
    ]],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never']
  }
};

//[build, ci, docs, feat, fix, perf, refactor, revert, style, test]

<|endoftext|>


<commit_before>'use strict';
const util = require('util');

/**
 * Reusable helper functions and defaults for effects.
 * Pass in the attribute/whatever else changes, along with the config.
 */

const defaultDuration = 10 * 1000;

const getTargetName = config => config.player ?
	config.player.getName() : config.target.getShortDesc('en');

const debuff = (attribute, config) => {
	config.magnitude = -config.magnitude;
	return buff(attribute, config);
};

const buff = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration || defaultDuration,
		activate: () => {
			config.target.setAttribute(attribute, original + config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const buffWithMax = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const max = 'max_' + attribute;
	const original = config.player.getAttribute(attribute);
	const originalMax = config.player.getAttribute(max);

	return {
		activate: () => {
			config.player.setAttribute(max, originalMax + config.magnitude);
			config.player.setAttribute(attribute, original + config.magnitude);
		},
		deactivate: () => {
			config.player.setAttribute(max, originalMax);
			config.player.setAttribute(attribute, Math.min(originalMax, config.player.getAttribute(attribute)));
			if (config.deactivate) { config.deactivate(); }
		},
		duration: config.duration || defaultDuration,
		event: config.event

	};
};

const multiply = (attribute, config) => {
	util.log('Multiplying ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration || defaultDuration,
		activate: () => {
			config.target.setAttribute(attribute, original * config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const Effects = {
  /**
   * Slow
	 * config.target: NPC to slow
	 * config.magnitude: amount to slow by (.5 would be half)
	 * [config.duration]: time in ms to slow for
	 * [config.deactivate]: function to execute after duration is over
   */
  slow: config => multiply('speed', config),

	/**
	 * Haste
	 * config.player: Player doing the targeting (or hasting themselves)
	 * config.targer: Player targeted
	 * config.magnitude
	 * [config.duration]: time in ms to haste for
	 * [config.deactivate]: function to execute after haste
	 */
	haste: config => {
		if (!config.target) { config.target = config.player; }
		return multiply('quickness', config);
	},

  /**
   * Health boost
	 * config.player: player whose health is boosted
   * config.magnitude: amount to boost health by
   * [config.duration]: amount of time to boost health
   * [config.event]: event to trigger health boost
   */
  health_boost:  config => buffWithMax('health', config),

	fortify: config => {
		if (!config.target) { config.target = config.player; }
		return buff('stamina', config);
	},

	// /**
	// * Ironskin
	// * +100 health stacked w/ +50 from leatherskin prereq
	// * +2 stamina, 1/2 quickness
	// */
	//
	// ironskin: config => {
	// 	// Effects.health_boost(config);
	// 	// Effects.haste({
	// 	// 	magnitude: .5,
	// 	// 	player: config.player,
	// 	// })
	// 	// Effects.fortify({
	// 	// 	magnitude: 2,
	// 	// 	player: config.player,
	// 	// });
	// }

};

exports.Effects = Effects;
<commit_msg>rm commented effect<commit_after>'use strict';
const util = require('util');

/**
 * Reusable helper functions and defaults for effects.
 * Pass in the attribute/whatever else changes, along with the config.
 */

const defaultDuration = 10 * 1000;

const getTargetName = config => config.player ?
	config.player.getName() : config.target.getShortDesc('en');

const debuff = (attribute, config) => {
	config.magnitude = -config.magnitude;
	return buff(attribute, config);
};

const buff = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration || defaultDuration,
		activate: () => {
			config.target.setAttribute(attribute, original + config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const buffWithMax = (attribute, config) => {
	util.log('Buffing ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const max = 'max_' + attribute;
	const original = config.player.getAttribute(attribute);
	const originalMax = config.player.getAttribute(max);

	return {
		activate: () => {
			config.player.setAttribute(max, originalMax + config.magnitude);
			config.player.setAttribute(attribute, original + config.magnitude);
		},
		deactivate: () => {
			config.player.setAttribute(max, originalMax);
			config.player.setAttribute(attribute, Math.min(originalMax, config.player.getAttribute(attribute)));
			if (config.deactivate) { config.deactivate(); }
		},
		duration: config.duration || defaultDuration,
		event: config.event

	};
};

const multiply = (attribute, config) => {
	util.log('Multiplying ' + attribute + ': ', getTargetName(config));
	util.log(config.magnitude);

	const original = config.target.getAttribute(attribute);
	return {
		duration: config.duration || defaultDuration,
		activate: () => {
			config.target.setAttribute(attribute, original * config.magnitude);
			if (config.activate) { config.activate(); }
		},
		deactivate: () => {
			if (config.target) {
				config.target.setAttribute(attribute, original);
				if (config.deactivate) { config.deactivate(); }
			}
		}
	};
};

const Effects = {
  /**
   * Slow
	 * config.target: NPC to slow
	 * config.magnitude: amount to slow by (.5 would be half)
	 * [config.duration]: time in ms to slow for
	 * [config.deactivate]: function to execute after duration is over
   */
  slow: config => multiply('speed', config),

	/**
	 * Haste
	 * config.player: Player doing the targeting (or hasting themselves)
	 * config.targer: Player targeted
	 * config.magnitude
	 * [config.duration]: time in ms to haste for
	 * [config.deactivate]: function to execute after haste
	 */
	haste: config => {
		if (!config.target) { config.target = config.player; }
		return multiply('quickness', config);
	},

  /**
   * Health boost
	 * config.player: player whose health is boosted
   * config.magnitude: amount to boost health by
   * [config.duration]: amount of time to boost health
   * [config.event]: event to trigger health boost
   */
  health_boost:  config => buffWithMax('health', config),

	fortify: config => {
		if (!config.target) { config.target = config.player; }
		return buff('stamina', config);
	},

};

exports.Effects = Effects;
<|endoftext|>


<commit_before>

angular
    .module('material.components.menu')
    .controller('mdMenuCtrl', MenuController);

/**
 * @ngInject
 */
function MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $rootScope, $q) {

  var menuContainer;
  var self = this;
  var triggerElement;

  this.nestLevel = parseInt($attrs.mdNestLevel, 10) || 0;

  /**
   * Called by our linking fn to provide access to the menu-content
   * element removed during link
   */
  this.init = function init(setMenuContainer, opts) {
    opts = opts || {};
    menuContainer = setMenuContainer;
    // Default element for ARIA attributes has the ngClick or ngMouseenter expression
    triggerElement = $element[0].querySelector('[ng-click],[ng-mouseenter]');
    triggerElement.setAttribute('aria-expanded', 'false');

    this.isInMenuBar = opts.isInMenuBar;
    this.nestedMenus = $mdUtil.nodesToArray(menuContainer[0].querySelectorAll('.md-nested-menu'));

    menuContainer.on('$mdInterimElementRemove', function() {
      self.isOpen = false;
    });

    var menuContainerId = 'menu_container_' + $mdUtil.nextUid();
    menuContainer.attr('id', menuContainerId);
    angular.element(triggerElement).attr({
      'aria-owns': menuContainerId,
      'aria-haspopup': 'true'
    });

    $scope.$on('$destroy', this.disableHoverListener);
  };

  var openMenuTimeout, menuItems, deregisterScopeListeners = [];
  this.enableHoverListener = function() {
    deregisterScopeListeners.push($rootScope.$on('$mdMenuOpen', function(event, el) {
      if (menuContainer[0].contains(el[0])) {
        self.currentlyOpenMenu = el.controller('mdMenu');
        self.isAlreadyOpening = false;
        self.currentlyOpenMenu.registerContainerProxy(self.triggerContainerProxy.bind(self));
      }
    }));
    deregisterScopeListeners.push($rootScope.$on('$mdMenuClose', function(event, el) {
      if (menuContainer[0].contains(el[0])) {
        self.currentlyOpenMenu = undefined;
      }
    }));
    menuItems = angular.element($mdUtil.nodesToArray(menuContainer[0].querySelectorAll('md-menu-item')));
    menuItems.on('mouseenter', self.handleMenuItemHover);
    menuItems.on('mouseleave', self.handleMenuItemMouseLeave);
  };

  this.disableHoverListener = function() {
    while (deregisterScopeListeners.length) {
      deregisterScopeListeners.shift()();
    }
    menuItems && menuItems.off('mouseenter', self.handleMenuItemHover);
    menuItems && menuItems.off('mouseleave', self.handleMenuMouseLeave);
  };

  this.handleMenuItemHover = function(event) {
    if (self.isAlreadyOpening) return;
    var nestedMenu = (
      event.target.querySelector('md-menu')
        || $mdUtil.getClosest(event.target, 'MD-MENU')
    );
    openMenuTimeout = $timeout(function() {
      if (nestedMenu) {
        nestedMenu = angular.element(nestedMenu).controller('mdMenu');
      }

      if (self.currentlyOpenMenu && self.currentlyOpenMenu != nestedMenu) {
        var closeTo = self.nestLevel + 1;
        self.currentlyOpenMenu.close(true, { closeTo: closeTo });
      } else if (nestedMenu && !nestedMenu.isOpen && nestedMenu.open) {
        self.isAlreadyOpening = true;
      }
      nestedMenu && nestedMenu.open();
    }, nestedMenu ? 100 : 250);
    var focusableTarget = event.currentTarget.querySelector('button:not([disabled])');
    focusableTarget && focusableTarget.focus();
  };

  this.handleMenuItemMouseLeave = function() {
    if (openMenuTimeout) {
      $timeout.cancel(openMenuTimeout);
      openMenuTimeout = undefined;
    }
  };

  /**
   * Uses the $mdMenu interim element service to open the menu contents
   */
  this.open = function openMenu(ev) {
    ev && ev.stopPropagation();
    ev && ev.preventDefault();
    if (self.isOpen) return;
    self.enableHoverListener();
    self.isOpen = true;
    triggerElement = triggerElement || (ev ? ev.target : $element[0]);
    triggerElement.setAttribute('aria-expanded', 'true');
    $scope.$emit('$mdMenuOpen', $element);
    $mdMenu.show({
      scope: $scope,
      mdMenuCtrl: self,
      nestLevel: self.nestLevel,
      element: menuContainer,
      target: triggerElement,
      preserveElement: true,
      parent: 'body'
    }).finally(function() {
      triggerElement.setAttribute('aria-expanded', 'false');
      self.disableHoverListener();
    });
  };

  // Expose a open function to the child scope for html to use
  $scope.$mdOpenMenu = this.open;

  $scope.$watch(function() { return self.isOpen; }, function(isOpen) {
    if (isOpen) {
      menuContainer.attr('aria-hidden', 'false');
      $element[0].classList.add('md-open');
      angular.forEach(self.nestedMenus, function(el) {
        el.classList.remove('md-open');
      });
    } else {
      menuContainer.attr('aria-hidden', 'true');
      $element[0].classList.remove('md-open');
    }
    $scope.$mdMenuIsOpen = self.isOpen;
  });

  this.focusMenuContainer = function focusMenuContainer() {
    var focusTarget = menuContainer[0].querySelector('[md-menu-focus-target]');
    if (!focusTarget) focusTarget = menuContainer[0].querySelector('.md-button');
    focusTarget.focus();
  };

  this.registerContainerProxy = function registerContainerProxy(handler) {
    this.containerProxy = handler;
  };

  this.triggerContainerProxy = function triggerContainerProxy(ev) {
    this.containerProxy && this.containerProxy(ev);
  };

  this.destroy = function() {
    return self.isOpen ? $mdMenu.destroy() : $q.when(false);
  };

  // Use the $mdMenu interim element service to close the menu contents
  this.close = function closeMenu(skipFocus, closeOpts) {
    if ( !self.isOpen ) return;
    self.isOpen = false;

    var eventDetails = angular.extend({}, closeOpts, { skipFocus: skipFocus });
    $scope.$emit('$mdMenuClose', $element, eventDetails);
    $mdMenu.hide(null, closeOpts);

    if (!skipFocus) {
      var el = self.restoreFocusTo || $element.find('button')[0];
      if (el instanceof angular.element) el = el[0];
      if (el) el.focus();
    }
  };

  /**
   * Build a nice object out of our string attribute which specifies the
   * target mode for left and top positioning
   */
  this.positionMode = function positionMode() {
    var attachment = ($attrs.mdPositionMode || 'target').split(' ');

    // If attachment is a single item, duplicate it for our second value.
    // ie. 'target' -> 'target target'
    if (attachment.length == 1) {
      attachment.push(attachment[0]);
    }

    return {
      left: attachment[0],
      top: attachment[1]
    };
  };

  /**
   * Build a nice object out of our string attribute which specifies
   * the offset of top and left in pixels.
   */
  this.offsets = function offsets() {
    var position = ($attrs.mdOffset || '0 0').split(' ').map(parseFloat);
    if (position.length == 2) {
      return {
        left: position[0],
        top: position[1]
      };
    } else if (position.length == 1) {
      return {
        top: position[0],
        left: position[0]
      };
    } else {
      throw Error('Invalid offsets specified. Please follow format <x, y> or <n>');
    }
  };
}
<commit_msg>fix(menu-bar): fix embeded menus closing immediately<commit_after>

angular
    .module('material.components.menu')
    .controller('mdMenuCtrl', MenuController);

/**
 * @ngInject
 */
function MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $rootScope, $q) {

  var menuContainer;
  var self = this;
  var triggerElement;

  this.nestLevel = parseInt($attrs.mdNestLevel, 10) || 0;

  /**
   * Called by our linking fn to provide access to the menu-content
   * element removed during link
   */
  this.init = function init(setMenuContainer, opts) {
    opts = opts || {};
    menuContainer = setMenuContainer;
    // Default element for ARIA attributes has the ngClick or ngMouseenter expression
    triggerElement = $element[0].querySelector('[ng-click],[ng-mouseenter]');
    triggerElement.setAttribute('aria-expanded', 'false');

    this.isInMenuBar = opts.isInMenuBar;
    this.nestedMenus = $mdUtil.nodesToArray(menuContainer[0].querySelectorAll('.md-nested-menu'));

    menuContainer.on('$mdInterimElementRemove', function() {
      self.isOpen = false;
    });

    var menuContainerId = 'menu_container_' + $mdUtil.nextUid();
    menuContainer.attr('id', menuContainerId);
    angular.element(triggerElement).attr({
      'aria-owns': menuContainerId,
      'aria-haspopup': 'true'
    });

    $scope.$on('$destroy', this.disableHoverListener);
  };

  var openMenuTimeout, menuItems, deregisterScopeListeners = [];
  this.enableHoverListener = function() {
    deregisterScopeListeners.push($rootScope.$on('$mdMenuOpen', function(event, el) {
      if (menuContainer[0].contains(el[0])) {
        self.currentlyOpenMenu = el.controller('mdMenu');
        self.isAlreadyOpening = false;
        self.currentlyOpenMenu.registerContainerProxy(self.triggerContainerProxy.bind(self));
      }
    }));
    deregisterScopeListeners.push($rootScope.$on('$mdMenuClose', function(event, el) {
      if (menuContainer[0].contains(el[0])) {
        self.currentlyOpenMenu = undefined;
      }
    }));
    menuItems = angular.element($mdUtil.nodesToArray(menuContainer[0].children[0].children));
    menuItems.on('mouseenter', self.handleMenuItemHover);
    menuItems.on('mouseleave', self.handleMenuItemMouseLeave);
  };

  this.disableHoverListener = function() {
    while (deregisterScopeListeners.length) {
      deregisterScopeListeners.shift()();
    }
    menuItems && menuItems.off('mouseenter', self.handleMenuItemHover);
    menuItems && menuItems.off('mouseleave', self.handleMenuMouseLeave);
  };

  this.handleMenuItemHover = function(event) {
    if (self.isAlreadyOpening) return;
    var nestedMenu = (
      event.target.querySelector('md-menu')
        || $mdUtil.getClosest(event.target, 'MD-MENU')
    );
    openMenuTimeout = $timeout(function() {
      if (nestedMenu) {
        nestedMenu = angular.element(nestedMenu).controller('mdMenu');
      }

      if (self.currentlyOpenMenu && self.currentlyOpenMenu != nestedMenu) {
        var closeTo = self.nestLevel + 1;
        self.currentlyOpenMenu.close(true, { closeTo: closeTo });
      } else if (nestedMenu && !nestedMenu.isOpen && nestedMenu.open) {
        self.isAlreadyOpening = true;
        nestedMenu.open();
      }
    }, nestedMenu ? 100 : 250);
    var focusableTarget = event.currentTarget.querySelector('button:not([disabled])');
    focusableTarget && focusableTarget.focus();
  };

  this.handleMenuItemMouseLeave = function() {
    if (openMenuTimeout) {
      $timeout.cancel(openMenuTimeout);
      openMenuTimeout = undefined;
    }
  };

  /**
   * Uses the $mdMenu interim element service to open the menu contents
   */
  this.open = function openMenu(ev) {
    ev && ev.stopPropagation();
    ev && ev.preventDefault();
    if (self.isOpen) return;
    self.enableHoverListener();
    self.isOpen = true;
    triggerElement = triggerElement || (ev ? ev.target : $element[0]);
    triggerElement.setAttribute('aria-expanded', 'true');
    $scope.$emit('$mdMenuOpen', $element);
    $mdMenu.show({
      scope: $scope,
      mdMenuCtrl: self,
      nestLevel: self.nestLevel,
      element: menuContainer,
      target: triggerElement,
      preserveElement: true,
      parent: 'body'
    }).finally(function() {
      triggerElement.setAttribute('aria-expanded', 'false');
      self.disableHoverListener();
    });
  };

  // Expose a open function to the child scope for html to use
  $scope.$mdOpenMenu = this.open;

  $scope.$watch(function() { return self.isOpen; }, function(isOpen) {
    if (isOpen) {
      menuContainer.attr('aria-hidden', 'false');
      $element[0].classList.add('md-open');
      angular.forEach(self.nestedMenus, function(el) {
        el.classList.remove('md-open');
      });
    } else {
      menuContainer.attr('aria-hidden', 'true');
      $element[0].classList.remove('md-open');
    }
    $scope.$mdMenuIsOpen = self.isOpen;
  });

  this.focusMenuContainer = function focusMenuContainer() {
    var focusTarget = menuContainer[0].querySelector('[md-menu-focus-target]');
    if (!focusTarget) focusTarget = menuContainer[0].querySelector('.md-button');
    focusTarget.focus();
  };

  this.registerContainerProxy = function registerContainerProxy(handler) {
    this.containerProxy = handler;
  };

  this.triggerContainerProxy = function triggerContainerProxy(ev) {
    this.containerProxy && this.containerProxy(ev);
  };

  this.destroy = function() {
    return self.isOpen ? $mdMenu.destroy() : $q.when(false);
  };

  // Use the $mdMenu interim element service to close the menu contents
  this.close = function closeMenu(skipFocus, closeOpts) {
    if ( !self.isOpen ) return;
    self.isOpen = false;

    var eventDetails = angular.extend({}, closeOpts, { skipFocus: skipFocus });
    $scope.$emit('$mdMenuClose', $element, eventDetails);
    $mdMenu.hide(null, closeOpts);

    if (!skipFocus) {
      var el = self.restoreFocusTo || $element.find('button')[0];
      if (el instanceof angular.element) el = el[0];
      if (el) el.focus();
    }
  };

  /**
   * Build a nice object out of our string attribute which specifies the
   * target mode for left and top positioning
   */
  this.positionMode = function positionMode() {
    var attachment = ($attrs.mdPositionMode || 'target').split(' ');

    // If attachment is a single item, duplicate it for our second value.
    // ie. 'target' -> 'target target'
    if (attachment.length == 1) {
      attachment.push(attachment[0]);
    }

    return {
      left: attachment[0],
      top: attachment[1]
    };
  };

  /**
   * Build a nice object out of our string attribute which specifies
   * the offset of top and left in pixels.
   */
  this.offsets = function offsets() {
    var position = ($attrs.mdOffset || '0 0').split(' ').map(parseFloat);
    if (position.length == 2) {
      return {
        left: position[0],
        top: position[1]
      };
    } else if (position.length == 1) {
      return {
        top: position[0],
        left: position[0]
      };
    } else {
      throw Error('Invalid offsets specified. Please follow format <x, y> or <n>');
    }
  };
}
<|endoftext|>


<commit_before>/**
* Module that contains interaction helpers for JSAV.
* Depends on core.js, anim.js
*/
(function($) {
  "use strict";
  var jsanim = JSAV.anim;
  JSAV.ext.effects = {
    /* toggles visibility of an element */
    _toggleVisible: function() {
      if (this.jsav._shouldAnimate()) { // only animate when playing, not when recording
        this.element.fadeToggle(this.jsav.SPEED);
      } else {
        this.element.toggle();
      }
      return [];
    },
    /* shows an element */
    show: function(options) {
      if (this.element.filter(":visible").size() === 0) {
        this._toggleVisible(options);
      }
      return this;
    },
    /* hides an element */
    hide: function(options) {
      if (this.element.filter(":visible").size() > 0) {
        this._toggleVisible(options);
      }
      return this;
    },
    swap: function($str1, $str2, translateY) {
      var $val1 = $str1.find("span.jsavvalue"),
          $val2 = $str2.find("span.jsavvalue"),
          posdiffX = JSAV.position($str1).left - JSAV.position($str2).left,
          posdiffY = translateY?JSAV.position($str1).top - JSAV.position($str2).top:0,
          $both = $($str1).add($str2),
          str1prevStyle = $str1.getstyles("color", "background-color"),
          str2prevStyle = $str2.getstyles("color", "background-color"),
          speed = this.SPEED/5,
          tmp;

      // ..swap the value elements...
      var val1 = $val1[0],
          val2 = $val2[0],
          aparent = val1.parentNode,
          asibling = val1.nextSibling===val2 ? val1 : val1.nextSibling;
      val2.parentNode.insertBefore(val1, val2);
      aparent.insertBefore(val2, asibling);

      // ..swap the values in the attributes..
      tmp = $str1.attr("data-value");
      $str1.attr("data-value", $str2.attr("data-value"));
      $str2.attr("data-value", tmp);

      // ..and finally animate..
      if (this._shouldAnimate()) {  // only animate when playing, not when recording
        if ('Raphael' in window) { // draw arrows only if Raphael is loaded
          var off1 = $val1.offset(),
              off2 = $val2.offset(),
              coff = this.canvas.offset(),
              x1 = off1.left - coff.left + $val1.outerWidth()/2,
              x2 = off2.left - coff.left + $val2.outerWidth()/2,
              y1 = off1.top - coff.top + $val1.outerHeight() + 5,
              y2 = y1,
              curve = 20,
              cx1 = x1,
              cx2 = x2,
              cy1 = y2 + curve,
              cy2 = y2 + curve,
              arrowStyle = "classic-wide-long";
          if (posdiffY > 1 || posdiffY < 1) {
            y2 = off2.top - coff.top + $val2.outerHeight() + 5;
            var angle = (y2 - y1) / (x2 - x1),
                c1 = Math.pow(y1, 2) - (curve*curve / (1 + angle*angle)),
                c2 = Math.pow(y2, 2) - (curve*curve / (1 + angle*angle));
            cy1 = y1 + Math.sqrt(y1*y1 - c1);
            cx1 = x1 - angle*Math.sqrt(y1*y1 - c1);
            cy2 = y2 + Math.sqrt(y2*y2 - c2);
            cx2 = x2 - angle*Math.sqrt(y2*y2 - c2);
          }
          // .. and draw a curved path with arrowheads
          var arr = this.getSvg().path("M" + x1 + "," + y1 + "C" + cx1 + "," + cy1 + " " + cx2 + "," + cy2 + " " + x2 + "," + y2).attr({"arrow-start": arrowStyle, "arrow-end": arrowStyle, "stroke-width": 5, "stroke":"lightGray"});
        }
        // .. then set the position so that the array appears unchanged..
        $val1.css({"transform": "translate(" + (posdiffX) + "px, " + (posdiffY) + "px)"});
        $val2.css({"transform": "translate(" + (-posdiffX) + "px, " + (-posdiffY) + "px)"});
        // .. animate the color ..
        $both.animate({"color": "red", "background-color": "pink"}, 3*speed, function() {
          // ..animate the translation to 0, so they'll be in their final positions..
          $val1.animate({"transform": "translate(0, 0)"}, 7*speed, 'linear');
          $val2.animate({"transform": "translate(0, 0)"}, 7*speed, 'linear',
            function() {
              if (arr) { arr.remove(); } // ..remove the arrows if they exist
              // ..and finally animate to the original styles.
              $str1.animate(str1prevStyle, speed);
              $str2.animate(str2prevStyle, speed);
          });
        });
      }
    }
  };
}(jQuery));<commit_msg>Added moveValue effect to move value from structure to another (#86)<commit_after>/**
* Module that contains interaction helpers for JSAV.
* Depends on core.js, anim.js
*/
(function($) {
  "use strict";
  var jsanim = JSAV.anim;
  JSAV.ext.effects = {
    /* toggles visibility of an element */
    _toggleVisible: function() {
      if (this.jsav._shouldAnimate()) { // only animate when playing, not when recording
        this.element.fadeToggle(this.jsav.SPEED);
      } else {
        this.element.toggle();
      }
      return [];
    },
    /* shows an element */
    show: function(options) {
      if (this.element.filter(":visible").size() === 0) {
        this._toggleVisible(options);
      }
      return this;
    },
    /* hides an element */
    hide: function(options) {
      if (this.element.filter(":visible").size() > 0) {
        this._toggleVisible(options);
      }
      return this;
    },
    moveValue: function() {
      // first we parse the passed arguments
      // possibilities are:
      //  - array, ind, array, ind
      //  - array, ind, node
      //  - node, array, ind
      //  - node, node
      var params = {
        args1: [],
        args2: [],
        from: arguments[0] // first param is always 1st structure
      };
      if (arguments.length === 2) { // two nodes passed
        params.to = arguments[1];
      } else if (arguments.length === 4) { // case of two arrays
        params.args1 = [ arguments[1] ];
        params.to = arguments[2];
        params.args2 = [ arguments[3] ];
      } else { // one array, one node
        if (typeof arguments[1] === "object") { // second param not number or string
          params.to = arguments[1];
          params.args2 = [ arguments[2] ];
        } else { // 2nd param is an index
          params.args1 = [ arguments[1] ];
          params.to = arguments[2];
        }
      }
      var doTheMove = function(opts) {
        // get the values of the from and to elements
        var val = opts.from.value.apply(opts.from, opts.args1),
            oldValue = opts.to.value.apply(opts.to, opts.args2),
            $fromValElem, $toValElem;
        // get the HTML elements for the values, for arrays, use the index
        if (opts.from.constructor === JSAV._types.ds.AVArray) {
          $fromValElem = opts.from.element.find("li:eq(" + opts.args1[0] + ") .jsavvalue");
        } else {
          $fromValElem = opts.from.element.find(".jsavvalue");
        }
        if (opts.to.constructor === JSAV._types.ds.AVArray) {
          $toValElem = opts.to.element.find("li:eq(" + opts.args2[0] + ") .jsavvalue");
        } else {
          $toValElem = opts.to.element.find(".jsavvalue");
        }

        // set the value in original structure to empty string or, if undoing, the old value
        opts.from.value.apply(opts.from, opts.args1.concat([opts.old?opts.old:"", {record: false}]));

        // set the value of the target structure
        opts.to.value.apply(opts.to, opts.args2.concat([val, {record: false}]));

        if (this._shouldAnimate()) {  // only animate when playing, not when recording
          $toValElem.position({of: $fromValElem}); // let jqueryUI position it on top of the from element
          $toValElem.animate({"left": "0", top: 0}, this.speed, 'linear'); // animate to final position
        }

        // return "reversed" parameters and the old value for undoing
        return [{
          from: opts.to,
          args1: opts.args2,
          to: opts.from,
          args2: opts.args1,
          old: oldValue
        }];
      };

      // wrap the doTheMove function to JSAV animatable function
      JSAV.anim(doTheMove).call(this, params);
    },
    swap: function($str1, $str2, translateY) {
      var $val1 = $str1.find("span.jsavvalue"),
          $val2 = $str2.find("span.jsavvalue"),
          posdiffX = JSAV.position($str1).left - JSAV.position($str2).left,
          posdiffY = translateY?JSAV.position($str1).top - JSAV.position($str2).top:0,
          $both = $($str1).add($str2),
          str1prevStyle = $str1.getstyles("color", "background-color"),
          str2prevStyle = $str2.getstyles("color", "background-color"),
          speed = this.SPEED/5,
          tmp;

      // ..swap the value elements...
      var val1 = $val1[0],
          val2 = $val2[0],
          aparent = val1.parentNode,
          asibling = val1.nextSibling===val2 ? val1 : val1.nextSibling;
      val2.parentNode.insertBefore(val1, val2);
      aparent.insertBefore(val2, asibling);

      // ..swap the values in the attributes..
      tmp = $str1.attr("data-value");
      $str1.attr("data-value", $str2.attr("data-value"));
      $str2.attr("data-value", tmp);

      // ..and finally animate..
      if (this._shouldAnimate()) {  // only animate when playing, not when recording
        if ('Raphael' in window) { // draw arrows only if Raphael is loaded
          var off1 = $val1.offset(),
              off2 = $val2.offset(),
              coff = this.canvas.offset(),
              x1 = off1.left - coff.left + $val1.outerWidth()/2,
              x2 = off2.left - coff.left + $val2.outerWidth()/2,
              y1 = off1.top - coff.top + $val1.outerHeight() + 5,
              y2 = y1,
              curve = 20,
              cx1 = x1,
              cx2 = x2,
              cy1 = y2 + curve,
              cy2 = y2 + curve,
              arrowStyle = "classic-wide-long";
          if (posdiffY > 1 || posdiffY < 1) {
            y2 = off2.top - coff.top + $val2.outerHeight() + 5;
            var angle = (y2 - y1) / (x2 - x1),
                c1 = Math.pow(y1, 2) - (curve*curve / (1 + angle*angle)),
                c2 = Math.pow(y2, 2) - (curve*curve / (1 + angle*angle));
            cy1 = y1 + Math.sqrt(y1*y1 - c1);
            cx1 = x1 - angle*Math.sqrt(y1*y1 - c1);
            cy2 = y2 + Math.sqrt(y2*y2 - c2);
            cx2 = x2 - angle*Math.sqrt(y2*y2 - c2);
          }
          // .. and draw a curved path with arrowheads
          var arr = this.getSvg().path("M" + x1 + "," + y1 + "C" + cx1 + "," + cy1 + " " + cx2 + "," + cy2 + " " + x2 + "," + y2).attr({"arrow-start": arrowStyle, "arrow-end": arrowStyle, "stroke-width": 5, "stroke":"lightGray"});
        }
        // .. then set the position so that the array appears unchanged..
        $val1.css({"transform": "translate(" + (posdiffX) + "px, " + (posdiffY) + "px)"});
        $val2.css({"transform": "translate(" + (-posdiffX) + "px, " + (-posdiffY) + "px)"});
        // .. animate the color ..
        $both.animate({"color": "red", "background-color": "pink"}, 3*speed, function() {
          // ..animate the translation to 0, so they'll be in their final positions..
          $val1.animate({"transform": "translate(0, 0)"}, 7*speed, 'linear');
          $val2.animate({"transform": "translate(0, 0)"}, 7*speed, 'linear',
            function() {
              if (arr) { arr.remove(); } // ..remove the arrows if they exist
              // ..and finally animate to the original styles.
              $str1.animate(str1prevStyle, speed);
              $str2.animate(str2prevStyle, speed);
          });
        });
      }
    }
  };
}(jQuery));<|endoftext|>


<commit_before>const expect = require("expect.js");

const {Kafka, Drainer, Publisher, PartitionDrainer} = require("./../../index.js");

const uuid = require("uuid");
const TEST_TOPIC = "sinek-test-topic-" + (process.env.KST_TOPIC || uuid.v4());
const CONSUMER_NAME = "sinek-consumer-" + uuid.v4();
const PRODUCER_NAME = "sinek-producer-" + uuid.v4();

const DUMMY_MESSAGE = {
    a: "funny",
    msg: "payload",
    that: "is super cool"
};

const MESSAGE_COUNT = 150;

const CONSUMER_TEST_LOGGER = {
    debug: msg => console.log("consumer: " + msg),
    //debug: msg => {}, //silence
    info: msg => console.log("consumer: " + msg),
    warn: msg => console.log("consumer: " + msg),
    error: msg => console.log("consumer: " + msg)
};

const PRODUCER_TEST_LOGGER = {
    debug: msg => console.log("producer: " + msg),
    info: msg => console.log("producer: " + msg),
    warn: msg => console.log("producer: " + msg),
    error: msg => console.log("producer: " + msg)
};

const CON_STR = "localhost:2181";
const DRAIN_TIMEOUT = 35000;

describe("Sinek INT", function(){

    let consumer = null;
    let producer = null;
    let consumedMessages = [];
    let lastConsumedSize = 0;
    let drainDone = false;
    let firstDrainFired = false;

    before(function(done){
        done();
    });

    after(function(done){

        if(consumer){
            consumer.close();
        }

        if(producer){
            producer.close();
        }

        setTimeout(done, 1500);
    });

    it("should be able to start a producer", function(done){

        const kp = new Kafka(CON_STR, PRODUCER_TEST_LOGGER);
        kp.becomeProducer([TEST_TOPIC], PRODUCER_NAME);

        kp.on("ready", () => {
            producer = new Publisher(kp);
            done();
        });

        kp.on("error", err => console.log("producer error: " + err));
    });

    it("should be able to start the a consumer", function(done){

        const kc = new Kafka(CON_STR, CONSUMER_TEST_LOGGER);
        kc.becomeConsumer([TEST_TOPIC], CONSUMER_NAME);

        kc.on("ready", () => {
            consumer = new Drainer(kc, 1);
            done();
        });

        kc.on("error", err => console.log("consumer error: " + err));
    });

    it("halt threshold", function(done){
        setTimeout(done, 500);
    });

    it("should be able to delete the topic if present", function(done){
        consumer.removeTopics([TEST_TOPIC]).then(rt => {
            console.log(rt);
            done();
        });
    });

    it("should be able to create topic", function(done){
        producer.createTopics([TEST_TOPIC]).then(ct => {
            console.log(ct);
            done();
        });
    });

    function populateQueue(){
        const map = [];
        const me = [1,2,3,4,5,6,7,8,9,10];
        for(let i = 0; i < MESSAGE_COUNT / me.length; i++){
            const batch = me.map(_ => JSON.stringify(DUMMY_MESSAGE));
            map.push(producer.send(TEST_TOPIC, batch));
        }
        return Promise.all(map);
    }

    it("should be able to publish messages", function(done){
        populateQueue().then(_ => {
            expect(producer.getStats().totalPublished).to.be.equal(MESSAGE_COUNT);
            done();
        });
    });

    it("halt threshold", function(done){
        setTimeout(done, 200);
    });

    it("should be able to drain messages from consumer", function(done){
        consumer.drain((message, _done) => {
            consumedMessages.push(message);
            _done();
        });
        done();
    });

    it("should be able to enforce offset", function(done){
        consumer.resume();
        done();
    });

    it("halt threshold", function(done){
        setTimeout(done, 200);
    });

    it("should have consumed a decent amount of messages", function(done){
        console.log(consumedMessages.length);

        //depending your zk and broker configuration this will not work
        //because you have not received any messages yet
        expect(consumedMessages.length >= MESSAGE_COUNT).to.be.equal(true);
        lastConsumedSize = consumedMessages.length;
        expect(consumedMessages[0].value.msg).to.be.equal(DUMMY_MESSAGE.msg);
        done();
    });

    it("should be able to drainOnce for all messages", function(done){
        consumer.stopDrain();
        consumer.DRAIN_INTV = 200; //speed up for testing
        consumer.drainOnce((message, _done) => {
            consumedMessages.push(message);
            _done();
        }, 760, DRAIN_TIMEOUT).then(r => {
            console.log(r);
            drainDone = true;
        });

        //listen once for first drain message
        let fdm = null;
        fdm = function(){
            consumer.removeListener("first-drain-message", fdm);
            firstDrainFired = true;
        };
        consumer.on("first-drain-message", fdm);
        done();
    });

    it("should be able to enforce offset", function(done){
        consumer.resume();
        done();
    });

    it("should be able to get stats", function(done){
        setTimeout(() => {
            console.log(consumer.getStats());
            console.log(producer.getStats());
            done();
        }, 250);
    });

    it("await drain done", function(done){
        this.timeout(DRAIN_TIMEOUT);
        let intv = null;
        intv = setInterval(() => {
            if(drainDone){
                clearInterval(intv);
                done();
            }
        }, 100);
    });

    xit("should have drained messages until stall", function(done){
        console.log(consumedMessages.length - lastConsumedSize);
        expect(consumedMessages.length).not.to.be.equal(lastConsumedSize);
        expect(drainDone).to.be.equal(true);
        expect(firstDrainFired).to.be.equal(true);
        console.log(consumedMessages[0], consumedMessages[100], consumedMessages[200], consumedMessages[250]);
        done();
    });

    it("should be able to close consumer", function(done){
       setTimeout(() => {
            consumer.close();
            consumer = null;
           done();
       }, 300);
    });

    it("should be able to setup partition drainer", function(done){

        //reset
        consumedMessages = [];
        firstDrainFired = false;
        drainDone = false;

        const kc = new Kafka(CON_STR, CONSUMER_TEST_LOGGER);
        kc.becomeConsumer([TEST_TOPIC], CONSUMER_NAME);

        kc.on("ready", () => {
            consumer = new PartitionDrainer(kc, 1);
            done();
        });

        kc.on("error", err => console.log("consumer error: " + err));
    });

    it("should be able to drainOnce again for all messages", function(done){

        consumer.DRAIN_INTV = 400; //speed up for testing
        consumer.drainOnce(TEST_TOPIC, (message, _done) => {
            consumedMessages.push(message);
            _done();
        }, 700, DRAIN_TIMEOUT).then(r => {
            console.log(r);
            drainDone = true;
        });

        //listen once for first drain message
        let fdm = null;
        fdm = function(){
            consumer.removeListener("first-drain-message", fdm);
            firstDrainFired = true;
        };
        consumer.on("first-drain-message", fdm);
        done();
    });

    it("await drain 2 done", function(done){
        this.timeout(DRAIN_TIMEOUT);

        let offset = 0;
        const pubint = setInterval(() => {
            offset++;
            consumer.raw.emit("message", {
                topic: TEST_TOPIC,
                partition: 0,
                value: "{}",
                offset
            });
        }, 1);

        consumer.raw.emit("message", {
            topic: "other-topic",
            partition: 0,
            value: "{}",
            offset: 1000
        });

        consumer.raw.emit("message", {
            topic: TEST_TOPIC,
            partition: "bad-partition",
            value: "{}",
            offset: 1001
        });

        consumer.raw.emit("message", {
            topic: TEST_TOPIC,
            partition: "no-offset",
            value: "{}"
        });

        setTimeout(() => {
            clearTimeout(pubint);
        }, MESSAGE_COUNT);

        let intv = null;
        intv = setInterval(() => {

            console.log(consumer.getStats());

            if(drainDone){
                clearInterval(intv);
                done();
            }
        }, 500);
    });

    it("should have drained messages until stall 2", function(done){
        console.log(consumedMessages.length);
        expect(consumedMessages.length).not.to.be.equal(0);
        expect(consumedMessages[0].offset).not.to.be.equal(consumedMessages[1].offset);
        expect(consumedMessages[1].offset).not.to.be.equal(consumedMessages[2].offset);
        expect(consumedMessages[2].offset).not.to.be.equal(consumedMessages[3].offset);
        expect(consumedMessages[3].offset).not.to.be.equal(consumedMessages[4].offset);
        expect(drainDone).to.be.equal(true);
        expect(firstDrainFired).to.be.equal(true);
        console.log(consumedMessages[0], consumedMessages[100], consumedMessages[200], consumedMessages[250]);
        done();
    });
});
<commit_msg>Update Sinek.test.js<commit_after>const expect = require("expect.js");

const {Kafka, Drainer, Publisher, PartitionDrainer} = require("./../../index.js");

const uuid = require("uuid");
const TEST_TOPIC = "sinek-test-topic-" + (process.env.KST_TOPIC || uuid.v4());
const CONSUMER_NAME = "sinek-consumer-" + uuid.v4();
const PRODUCER_NAME = "sinek-producer-" + uuid.v4();

const DUMMY_MESSAGE = {
    a: "funny",
    msg: "payload",
    that: "is super cool"
};

const MESSAGE_COUNT = 150;

const CONSUMER_TEST_LOGGER = {
    debug: msg => console.log("consumer: " + msg),
    //debug: msg => {}, //silence
    info: msg => console.log("consumer: " + msg),
    warn: msg => console.log("consumer: " + msg),
    error: msg => console.log("consumer: " + msg)
};

const PRODUCER_TEST_LOGGER = {
    debug: msg => console.log("producer: " + msg),
    info: msg => console.log("producer: " + msg),
    warn: msg => console.log("producer: " + msg),
    error: msg => console.log("producer: " + msg)
};

const CON_STR = "localhost:2181";
const DRAIN_TIMEOUT = 35000;

describe("Sinek INT", function(){

    let consumer = null;
    let producer = null;
    let consumedMessages = [];
    let lastConsumedSize = 0;
    let drainDone = false;
    let firstDrainFired = false;

    before(function(done){
        done();
    });

    after(function(done){

        if(consumer){
            consumer.close();
        }

        if(producer){
            producer.close();
        }

        setTimeout(done, 1500);
    });

    it("should be able to start a producer", function(done){

        const kp = new Kafka(CON_STR, PRODUCER_TEST_LOGGER);
        kp.becomeProducer([TEST_TOPIC], PRODUCER_NAME);

        kp.on("ready", () => {
            producer = new Publisher(kp);
            done();
        });

        kp.on("error", err => console.log("producer error: " + err));
    });

    it("should be able to start the a consumer", function(done){

        const kc = new Kafka(CON_STR, CONSUMER_TEST_LOGGER);
        kc.becomeConsumer([TEST_TOPIC], CONSUMER_NAME);

        kc.on("ready", () => {
            consumer = new Drainer(kc, 1);
            done();
        });

        kc.on("error", err => console.log("consumer error: " + err));
    });

    it("halt threshold", function(done){
        setTimeout(done, 500);
    });

    xit("should be able to delete the topic if present", function(done){
        consumer.removeTopics([TEST_TOPIC]).then(rt => {
            console.log(rt);
            done();
        });
    });

    xit("should be able to create topic", function(done){
        producer.createTopics([TEST_TOPIC]).then(ct => {
            console.log(ct);
            done();
        });
    });

    function populateQueue(){
        const map = [];
        const me = [1,2,3,4,5,6,7,8,9,10];
        for(let i = 0; i < MESSAGE_COUNT / me.length; i++){
            const batch = me.map(_ => JSON.stringify(DUMMY_MESSAGE));
            map.push(producer.send(TEST_TOPIC, batch));
        }
        return Promise.all(map);
    }

    it("should be able to publish messages", function(done){
        populateQueue().then(_ => {
            expect(producer.getStats().totalPublished).to.be.equal(MESSAGE_COUNT);
            done();
        });
    });

    it("halt threshold", function(done){
        setTimeout(done, 1000);
    });

    it("should be able to drain messages from consumer", function(done){
        consumer.drain((message, _done) => {
            consumedMessages.push(message);
            _done();
        });
        done();
    });

    it("halt threshold", function(done){
        setTimeout(done, 500);
    });

    xit("should have consumed a decent amount of messages", function(done){
        console.log(consumedMessages.length);

        //depending your zk and broker configuration this will not work
        //because you have not received any messages yet
        expect(consumedMessages.length >= MESSAGE_COUNT).to.be.equal(true);
        lastConsumedSize = consumedMessages.length;
        expect(consumedMessages[0].value.msg).to.be.equal(DUMMY_MESSAGE.msg);
        done();
    });

    it("should be able to drainOnce for all messages", function(done){
        consumer.stopDrain();
        consumer.DRAIN_INTV = 200; //speed up for testing
        consumer.drainOnce((message, _done) => {
            consumedMessages.push(message);
            _done();
        }, 760, DRAIN_TIMEOUT).then(r => {
            console.log(r);
            drainDone = true;
        });

        //listen once for first drain message
        let fdm = null;
        fdm = function(){
            consumer.removeListener("first-drain-message", fdm);
            firstDrainFired = true;
        };
        consumer.on("first-drain-message", fdm);
        done();
    });

    it("should be able to enforce offset", function(done){
        consumer.resume();
        done();
    });

    it("should be able to get stats", function(done){
        setTimeout(() => {
            console.log(consumer.getStats());
            console.log(producer.getStats());
            done();
        }, 250);
    });

    it("await drain done", function(done){
        this.timeout(DRAIN_TIMEOUT);
        let intv = null;
        intv = setInterval(() => {
            if(drainDone){
                clearInterval(intv);
                done();
            }
        }, 100);
    });

    xit("should have drained messages until stall", function(done){
        console.log(consumedMessages.length - lastConsumedSize);
        expect(consumedMessages.length).not.to.be.equal(lastConsumedSize);
        expect(drainDone).to.be.equal(true);
        expect(firstDrainFired).to.be.equal(true);
        console.log(consumedMessages[0], consumedMessages[100], consumedMessages[200], consumedMessages[250]);
        done();
    });

    it("should be able to close consumer", function(done){
       setTimeout(() => {
            consumer.close();
            consumer = null;
           done();
       }, 300);
    });

    it("should be able to setup partition drainer", function(done){

        //reset
        consumedMessages = [];
        firstDrainFired = false;
        drainDone = false;

        const kc = new Kafka(CON_STR, CONSUMER_TEST_LOGGER);
        kc.becomeConsumer([TEST_TOPIC], CONSUMER_NAME);

        kc.on("ready", () => {
            consumer = new PartitionDrainer(kc, 1);
            done();
        });

        kc.on("error", err => console.log("consumer error: " + err));
    });

    it("should be able to drainOnce again for all messages", function(done){

        consumer.DRAIN_INTV = 400; //speed up for testing
        consumer.drainOnce(TEST_TOPIC, (message, _done) => {
            consumedMessages.push(message);
            _done();
        }, 700, DRAIN_TIMEOUT).then(r => {
            console.log(r);
            drainDone = true;
        });

        //listen once for first drain message
        let fdm = null;
        fdm = function(){
            consumer.removeListener("first-drain-message", fdm);
            firstDrainFired = true;
        };
        consumer.on("first-drain-message", fdm);
        done();
    });

    it("await drain 2 done", function(done){
        this.timeout(DRAIN_TIMEOUT);

        let offset = 0;
        const pubint = setInterval(() => {
            offset++;
            consumer.raw.emit("message", {
                topic: TEST_TOPIC,
                partition: 0,
                value: "{}",
                offset
            });
        }, 1);

        consumer.raw.emit("message", {
            topic: "other-topic",
            partition: 0,
            value: "{}",
            offset: 1000
        });

        consumer.raw.emit("message", {
            topic: TEST_TOPIC,
            partition: "bad-partition",
            value: "{}",
            offset: 1001
        });

        consumer.raw.emit("message", {
            topic: TEST_TOPIC,
            partition: "no-offset",
            value: "{}"
        });

        setTimeout(() => {
            clearTimeout(pubint);
        }, MESSAGE_COUNT);

        let intv = null;
        intv = setInterval(() => {

            console.log(consumer.getStats());

            if(drainDone){
                clearInterval(intv);
                done();
            }
        }, 500);
    });

    it("should have drained messages until stall 2", function(done){
        console.log(consumedMessages.length);
        expect(consumedMessages.length).not.to.be.equal(0);
        expect(consumedMessages[0].offset).not.to.be.equal(consumedMessages[1].offset);
        expect(consumedMessages[1].offset).not.to.be.equal(consumedMessages[2].offset);
        expect(consumedMessages[2].offset).not.to.be.equal(consumedMessages[3].offset);
        expect(consumedMessages[3].offset).not.to.be.equal(consumedMessages[4].offset);
        expect(drainDone).to.be.equal(true);
        expect(firstDrainFired).to.be.equal(true);
        console.log(consumedMessages[0], consumedMessages[100], consumedMessages[200], consumedMessages[250]);
        done();
    });
});
<|endoftext|>