<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        var modulemapper = require('cordova/modulemapper');

        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
        modulemapper.mapModules(window);

        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        // create global Mojo object if it does not exist
        Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    },
    merges: {
        navigator: {
            children: {
                service: {
                    path: "cordova/plugin/webos/service"
                },
                application: {
                    path: "cordova/plugin/webos/application"
                },
                window: {
                    path: "cordova/plugin/webos/window"
                },
                orientation: {
                    path: "cordova/plugin/webos/orientation"
                },
                keyboard: {
                    path: "cordova/plugin/webos/keyboard"
                }
            }
        }
    }
};
<commit_msg>[webos] modulemapper refactor for platform plugins.<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        var modulemapper = require('cordova/modulemapper');

        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);

        modulemapper.merges('cordova/plugin/webos/service', 'navigator.service');
        modulemapper.merges('cordova/plugin/webos/application', 'navigator.application');
        modulemapper.merges('cordova/plugin/webos/window', 'navigator.window');
        modulemapper.merges('cordova/plugin/webos/orientation', 'navigator.orientation');
        modulemapper.merges('cordova/plugin/webos/keyboard', 'navigator.keyboard');

        modulemapper.mapModules(window);

        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        // create global Mojo object if it does not exist
        Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    }
};
<|endoftext|>


<commit_before>import eventsTest from './events'

const validate = (events, stimuli, headers, jsonContents) => {
  return eventsTest(events, stimuli, headers, jsonContents)
}

export default validate
<commit_msg>Directly export validation function instead of wrapping it<commit_after>import eventsTest from './events'

export default eventsTest
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { StyleSheet, Text, View, Animated, Easing, TouchableOpacity, PixelRatio } from 'react-native';
import ActionButtonItem from './ActionButtonItem';

const alignItemsMap = {
  "center" : "center",
  "left"  : "flex-start",
  "right" : "flex-end"
}

export default class ActionButton extends Component {

  constructor(props) {
    super(props);

    this.state = {
      active: props.active,
      btnOutRange: props.btnOutRange || props.buttonColor || 'rgba(0,0,0,1)',
      btnOutRangeTxt: props.btnOutRangeTxt || props.buttonTextColor || 'rgba(255,255,255,1)',
      anim: new Animated.Value(props.active ? 1 : 0),
    }

    this.timeout = null;
    this.setPositionAndSizeByType();
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      ...nextProps
    });
  }

  setPositionAndSizeByType() {
    let position, offsetX, offsetY, size;

    if (this.props.type == 'tab') {
      position = 'center',
      offsetX  = 10,
      offsetY  = 4,
      size     = 42;
    } else {
      position = 'right',
      offsetX  = 30,
      offsetY  = 30,
      size     = 56;
    }

    this.state.position = this.props.position || position;
    this.state.offsetX  = this.props.offsetX  || offsetX ;
    this.state.offsetY  = this.props.offsetY  || offsetY;
    this.state.size     = this.props.size     || size;
  }

  //////////////////////
  // STYLESHEET GETTERS
  //////////////////////

  getContainerStyles() {
    return [styles.overlay, this.getOrientation(), this.getOffsetXY()];
  }

  getActionButtonStyles() {
    return [styles.actionBarItem, this.getButtonSize()];
  }

  getOrientation() {
    return { alignItems: alignItemsMap[this.state.position] };
  }

  getButtonSize() {
    return {
      width: this.state.size,
      height: this.state.size,
    }
  }

  getOffsetXY() {
    return {
      paddingHorizontal: this.state.offsetX,
      paddingBottom: this.state.offsetY
    };
  }

  getActionsStyle() {
    return [ styles.actionsVertical, this.getOrientation() ];
  }

  //////////////////////
  // RENDER METHODS
  //////////////////////

  render() {
    return (
      <View pointerEvents="box-none" style={styles.overlay}>
        <Animated.View pointerEvents="none" style={[styles.overlay, {
          backgroundColor: this.props.bgColor,
          opacity: this.state.anim
        }]}>
          {this.props.backdrop}
        </Animated.View>
        <View pointerEvents="box-none" style={this.getContainerStyles()}>
          {this.props.children && this._renderActions()}
          {this._renderButton()}
        </View>
      </View>
    );
  }

  _renderButton() {
    return (
      <View style={this.getActionButtonStyles()}>
        <TouchableOpacity
          activeOpacity={0.85}
          onLongPress={this.props.onLongPress}
          onPress={() => {
            this.props.onPress()
            if (this.props.children) this.animateButton()
          }}>
          <Animated.View
            style={[styles.btn, {
              width: this.state.size,
              height: this.state.size,
              borderRadius: this.state.size / 2,
              backgroundColor: this.state.anim.interpolate({
                inputRange: [0, 1],
                outputRange: [this.props.buttonColor, this.state.btnOutRange]
              }),
              transform: [{
                  scale: this.state.anim.interpolate({
                    inputRange: [0, 1],
                    outputRange: [1, this.props.outRangeScale]
                  }),
                }, {
                  rotate: this.state.anim.interpolate({
                    inputRange: [0, 1],
                    outputRange: ['0deg', this.props.degrees + 'deg']
                  })
                }],
            }]}>
            {this._renderButtonIcon()}
          </Animated.View>
        </TouchableOpacity>
      </View>
    );
  }

  _renderButtonIcon() {
    if (this.props.icon) return this.props.icon

    return (
      <Animated.Text style={[styles.btnText, {
        color: this.state.anim.interpolate({
          inputRange: [0, 1],
          outputRange: [this.props.buttonTextColor, this.state.btnOutRangeTxt]
        })
      }]}>
        +
      </Animated.Text>
    )
  }

  _renderActions() {
    if (!this.state.active) return null;

    let actionButtons = this.props.children

    if (!Array.isArray(this.props.children)) {
      actionButtons = [this.props.children]
    }

    return (
        <TouchableOpacity
          style={this.getActionsStyle()}
          activeOpacity={1}
          onPress={() => { this.reset() }}>
          {actionButtons.map((ActionButton, index) => {
            return (
              <ActionButtonItem
                key={index}
                position={this.state.position}
                spacing={this.props.spacing}
                anim={this.state.anim}
                size={this.state.size}
                btnColor={this.state.btnOutRange}
                {...ActionButton.props}
                onPress={() => {
                  if (this.props.autoInactive){
                    this.timeout = setTimeout(() => {
                      this.reset();
                    }, 200);
                  }
                  ActionButton.props.onPress();
                }}
              />
            )
          })}
        </TouchableOpacity>
    );
  }

  //////////////////////
  // Animation Methods
  //////////////////////

  animateButton() {
    if (this.state.active) return this.reset();

    Animated.spring(this.state.anim, {
       toValue: 1,
       duration: 250,
    }).start();

    this.setState({ active: true });
  }

  reset() {
    Animated.spring(this.state.anim, {
      toValue: 0,
      duration: 250,
    }).start();

    setTimeout(() => {
      this.setState({ active: false });
    }, 250);
  }
}

ActionButton.Item = ActionButtonItem;

ActionButton.propTypes = {
  active: PropTypes.bool,

  type: PropTypes.oneOf(['float', 'tab']),
  position: PropTypes.string,

  bgColor: PropTypes.string,
  buttonColor: PropTypes.string,
  buttonTextColor: PropTypes.string,

  offsetX : PropTypes.number,
  offsetY: PropTypes.number,
  spacing: PropTypes.number,
  size: PropTypes.number,
  autoInactive: PropTypes.bool,
  onPress: PropTypes.func,
  backdrop: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.object
]),
  degrees: PropTypes.number
};

ActionButton.defaultProps = {
  active: false,
  type: 'float',
  bgColor: 'transparent',
  buttonColor: 'rgba(0,0,0,1)',
  buttonTextColor: 'rgba(255,255,255,1)',
  spacing: 20,
  outRangeScale: 1,
  autoInactive: true,
  onPress: () => {},
  backdrop: false,
  degrees: 135
};

const styles = StyleSheet.create({
  overlay: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    top: 0,
    backgroundColor: 'transparent',
    justifyContent: 'flex-end',
  },
  actionBarItem: {
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'transparent',
  },
  btn: {
    justifyContent: 'center',
    alignItems: 'center',
    shadowOpacity: 0.3,
    shadowOffset: {
      width: 0, height: 1,
    },
    shadowColor: '#444',
    shadowRadius: 1,
  },
  btnText: {
    marginTop: -4,
    fontSize: 24,
    backgroundColor: 'transparent',
    position: 'relative',
  },
  actionsVertical: {
    flex: 1,
    justifyContent: 'flex-end',
    flexDirection: 'column',
  },
});
<commit_msg>Update AcionButton.js<commit_after>import React, { Component, PropTypes } from 'react';
import { StyleSheet, Text, View, Animated, Easing, TouchableOpacity, PixelRatio } from 'react-native';
import ActionButtonItem from './ActionButtonItem';

const alignItemsMap = {
  "center" : "center",
  "left"  : "flex-start",
  "right" : "flex-end"
}

export default class ActionButton extends Component {

  constructor(props) {
    super(props);

    this.state = {
      active: props.active,
      btnOutRange: props.btnOutRange || props.buttonColor || 'rgba(0,0,0,1)',
      btnOutRangeTxt: props.btnOutRangeTxt || props.buttonTextColor || 'rgba(255,255,255,1)',
      anim: new Animated.Value(props.active ? 1 : 0),
    }

    this.timeout = null;
    this.setPositionAndSizeByType();
  }

  componentWillUnmount() {
    clearTimeout(this.timeout);
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      ...nextProps
    });
  }

  setPositionAndSizeByType() {
    let position, offsetX, offsetY, size;

    if (this.props.type == 'tab') {
      position = 'center',
      offsetX  = 10,
      offsetY  = 4,
      size     = 42;
    } else {
      position = 'right',
      offsetX  = 30,
      offsetY  = 30,
      size     = 56;
    }

    this.state.position = this.props.position || position;
    this.state.offsetX  = this.props.offsetX  || offsetX ;
    this.state.offsetY  = this.props.offsetY  || offsetY;
    this.state.size     = this.props.size     || size;
  }

  //////////////////////
  // STYLESHEET GETTERS
  //////////////////////

  getContainerStyles() {
    return [styles.overlay, this.getOrientation(), this.getOffsetXY()];
  }

  getActionButtonStyles() {
    return [styles.actionBarItem, this.getButtonSize()];
  }

  getOrientation() {
    return { alignItems: alignItemsMap[this.state.position] };
  }

  getButtonSize() {
    return {
      width: this.state.size,
      height: this.state.size,
    }
  }

  getOffsetXY() {
    return {
      paddingHorizontal: this.state.offsetX,
      paddingBottom: this.state.offsetY
    };
  }

  getActionsStyle() {
    return [ styles.actionsVertical, this.getOrientation() ];
  }

  //////////////////////
  // RENDER METHODS
  //////////////////////

  render() {
    return (
      <View pointerEvents="box-none" style={styles.overlay}>
        <Animated.View style={[styles.overlay, {
          backgroundColor: this.props.bgColor,
          opacity: this.state.anim
        }]}>
          {this.props.backdrop}
        </Animated.View>
        <View pointerEvents="box-none" style={this.getContainerStyles()}>
          {this.props.children && this._renderActions()}
          {this._renderButton()}
        </View>
      </View>
    );
  }

  _renderButton() {
    return (
      <View style={this.getActionButtonStyles()}>
        <TouchableOpacity
          activeOpacity={0.85}
          onLongPress={this.props.onLongPress}
          onPress={() => {
            this.props.onPress()
            if (this.props.children) this.animateButton()
          }}>
          <Animated.View
            style={[styles.btn, {
              width: this.state.size,
              height: this.state.size,
              borderRadius: this.state.size / 2,
              backgroundColor: this.state.anim.interpolate({
                inputRange: [0, 1],
                outputRange: [this.props.buttonColor, this.state.btnOutRange]
              }),
              transform: [{
                  scale: this.state.anim.interpolate({
                    inputRange: [0, 1],
                    outputRange: [1, this.props.outRangeScale]
                  }),
                }, {
                  rotate: this.state.anim.interpolate({
                    inputRange: [0, 1],
                    outputRange: ['0deg', this.props.degrees + 'deg']
                  })
                }],
            }]}>
            {this._renderButtonIcon()}
          </Animated.View>
        </TouchableOpacity>
      </View>
    );
  }

  _renderButtonIcon() {
    if (this.props.icon) return this.props.icon

    return (
      <Animated.Text style={[styles.btnText, {
        color: this.state.anim.interpolate({
          inputRange: [0, 1],
          outputRange: [this.props.buttonTextColor, this.state.btnOutRangeTxt]
        })
      }]}>
        +
      </Animated.Text>
    )
  }

  _renderActions() {
    if (!this.state.active) return null;

    let actionButtons = this.props.children

    if (!Array.isArray(this.props.children)) {
      actionButtons = [this.props.children]
    }

    return (
        <TouchableOpacity
          style={this.getActionsStyle()}
          activeOpacity={1}
          onPress={() => { this.reset() }}>
          {actionButtons.map((ActionButton, index) => {
            return (
              <ActionButtonItem
                key={index}
                position={this.state.position}
                spacing={this.props.spacing}
                anim={this.state.anim}
                size={this.state.size}
                btnColor={this.state.btnOutRange}
                {...ActionButton.props}
                onPress={() => {
                  if (this.props.autoInactive){
                    this.timeout = setTimeout(() => {
                      this.reset();
                    }, 200);
                  }
                  ActionButton.props.onPress();
                }}
              />
            )
          })}
        </TouchableOpacity>
    );
  }

  //////////////////////
  // Animation Methods
  //////////////////////

  animateButton() {
    if (this.state.active) return this.reset();

    Animated.spring(this.state.anim, {
       toValue: 1,
       duration: 250,
    }).start();

    this.setState({ active: true });
  }

  reset() {
    Animated.spring(this.state.anim, {
      toValue: 0,
      duration: 250,
    }).start();

    setTimeout(() => {
      this.setState({ active: false });
    }, 250);
  }
}

ActionButton.Item = ActionButtonItem;

ActionButton.propTypes = {
  active: PropTypes.bool,

  type: PropTypes.oneOf(['float', 'tab']),
  position: PropTypes.string,

  bgColor: PropTypes.string,
  buttonColor: PropTypes.string,
  buttonTextColor: PropTypes.string,

  offsetX : PropTypes.number,
  offsetY: PropTypes.number,
  spacing: PropTypes.number,
  size: PropTypes.number,
  autoInactive: PropTypes.bool,
  onPress: PropTypes.func,
  backdrop: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.object
]),
  degrees: PropTypes.number
};

ActionButton.defaultProps = {
  active: false,
  type: 'float',
  bgColor: 'transparent',
  buttonColor: 'rgba(0,0,0,1)',
  buttonTextColor: 'rgba(255,255,255,1)',
  spacing: 20,
  outRangeScale: 1,
  autoInactive: true,
  onPress: () => {},
  backdrop: false,
  degrees: 135
};

const styles = StyleSheet.create({
  overlay: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    top: 0,
    backgroundColor: 'transparent',
    justifyContent: 'flex-end',
  },
  actionBarItem: {
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'transparent',
  },
  btn: {
    justifyContent: 'center',
    alignItems: 'center',
    shadowOpacity: 0.3,
    shadowOffset: {
      width: 0, height: 1,
    },
    shadowColor: '#444',
    shadowRadius: 1,
  },
  btnText: {
    marginTop: -4,
    fontSize: 24,
    backgroundColor: 'transparent',
    position: 'relative',
  },
  actionsVertical: {
    flex: 1,
    justifyContent: 'flex-end',
    flexDirection: 'column',
  },
});
<|endoftext|>


<commit_before>require('../support/test_helper');

var assert = require('../support/assert');
var step = require('step');
var Windshaft = require('../../lib/windshaft');
var ServerOptions = require('../support/server_options');
var testClient = require('../support/test_client_old');

describe('multilayer error cases', function() {

    var server = new Windshaft.Server(ServerOptions);
    server.setMaxListeners(0);

    it("layergroup with no cartocss_version", function(done) {
      var layergroup =  {
        version: '1.0.0',
        layers: [
           { options: {
               sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2',
               cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }'
             } }
        ]
      };
      assert.response(server, {
          url: '/database/windshaft_test/layergroup',
          method: 'POST',
          headers: {'Content-Type': 'application/json' },
          data: JSON.stringify(layergroup)
      }, {}, function(res) {
          assert.equal(res.statusCode, 400, res.body);
          var parsedBody = JSON.parse(res.body);
          assert.deepEqual(parsedBody, {errors:["Missing cartocss_version for layer 0 options"]});
          done();
      });
    });

    it("sql/cartocss combination errors", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [{ options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer [missing=1] { line-width:16; }'
        }}]
      };
      assert.response(server, {
          url: '/database/windshaft_test/layergroup',
          method: 'POST',
          headers: {'Content-Type': 'application/json' },
          data: JSON.stringify(layergroup)
      }, {}, function(res) {
        try {
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed);
          assert.equal(parsed.errors.length, 1);
          var error = parsed.errors[0];
          assert.ok(error.match(/column "missing" does not exist/m), error);
          // cannot check for error starting with style0 until a new enough mapnik
          // is used: https://github.com/mapnik/mapnik/issues/1924
          //assert.ok(error.match(/^style0/), "Error doesn't start with style0: " + error);
          // TODO: check which layer introduced the problem ?
          done();
        } catch (err) { done(err); }
      });
    });

    it("sql/interactivity combination error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }',
           interactivity: 'i'
          }},
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }'
          }},
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }',
           interactivity: 'missing'
          }}
        ]
      };
      assert.response(server, {
          url: '/database/windshaft_test/layergroup',
          method: 'POST',
          headers: {'Content-Type': 'application/json' },
          data: JSON.stringify(layergroup)
      }, {}, function(res) {
        try {
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed);
          assert.equal(parsed.errors.length, 1);
          var error = parsed.errors[0];
          assert.ok(error.match(/column "missing" does not exist/m), error);
          // TODO: check which layer introduced the problem ?
          done();
        } catch (err) { done(err); }
      });
    });

    it("blank CartoCSS error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style { line-width:16 }',
           interactivity: 'i'
          }},
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '',
           interactivity: 'i'
          }}
        ]
      };
      assert.response(server, {
          url: '/database/windshaft_test/layergroup',
          method: 'POST',
          headers: {'Content-Type': 'application/json' },
          data: JSON.stringify(layergroup)
      }, {}, function(res) {
        try {
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed);
          assert.equal(parsed.errors.length, 1);
          var error = parsed.errors[0];
          assert.ok(error.match(/^style1: CartoCSS is empty/), error);
          done();
        } catch (err) { done(err); }
      });
    });

    it("Invalid mapnik-geometry-type CartoCSS error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }'
          }},
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }'
          }}
        ]
      };
      assert.response(server, {
          url: '/database/windshaft_test/layergroup',
          method: 'POST',
          headers: {'Content-Type': 'application/json' },
          data: JSON.stringify(layergroup)
      }, {}, function(res) {
        try {
          assert.equal(res.statusCode, 400, res.statusCode + ': ' + res.body);
          var parsed = JSON.parse(res.body);
          assert.ok(parsed);
          assert.equal(parsed.errors.length, 1);
          var error = parsed.errors[0];
          // carto-0.9.3 used to say "Failed to parse expression",
          // carto-0.9.5 says "not a valid keyword"
          assert.ok(error.match(/^style0:.*(Failed|not a valid)/), error);
          // TODO: check which layer introduced the problem ?
          done();
        } catch (err) { done(err); }
      });
    });

    it("post'ing style with non existent column in filter returns 400 with error", function(done) {
        var layergroup =  {
            version: '1.0.1',
            layers: [
                { options: {
                    sql: 'select * from test_table limit 1',
                    cartocss: '#test_table::outline[address="one"], [address="two"] { marker-fill: red; }',
                    cartocss_version: '2.0.2',
                    interactivity: [ 'cartodb_id' ]
                } },
                { options: {
                    sql: 'select * from test_big_poly limit 1',
                    cartocss: '#test_big_poly { marker-fill:blue }',
                    cartocss_version: '2.0.2',
                    interactivity: [ 'cartodb_id' ]
                } }
            ]
        };

        assert.response(server, {
            url: '/database/windshaft_test/layergroup',
            method: 'POST',
            headers: {'Content-Type': 'application/json' },
            data: JSON.stringify(layergroup)
        }, {}, function(res) {
            assert.equal(res.statusCode, 400, res.body);
            var parsed = JSON.parse(res.body);
            assert.equal(parsed.errors.length, 1);
            var error = parsed.errors[0];
            assert.ok(error.match(/column "address" does not exist/m), error);
            done();
        });
    });

    // See https://github.com/Vizzuality/Windshaft/issues/31
    it('bogus sql raises 400 status code', function(done) {
        var bogusSqlMapConfig = testClient.singleLayerMapConfig('BOGUS FROM test_table');
        testClient.createLayergroup(bogusSqlMapConfig, { statusCode: 400 }, function(err, res) {
            assert.ok(/syntax error/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it('bogus sql raises 200 status code for jsonp', function(done) {
        var bogusSqlMapConfig = testClient.singleLayerMapConfig('bogus');
        var options = {
            method: 'GET',
            callbackName: 'test',
            headers: {
                'Content-Type': 'text/javascript; charset=utf-8'
            }
        };
        testClient.createLayergroup(bogusSqlMapConfig, options, function(err, res) {
            assert.ok(/^test\(/.test(res.body), "Body start expected callback name: " + res.body);
            assert.ok(/syntax error/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it('query not selecting the_geom raises 200 status code for jsonp instead of 404', function(done) {
        var noGeomMapConfig = testClient.singleLayerMapConfig('select null::geometry the_geom_wadus');
        var options = {
            method: 'GET',
            callbackName: 'test',
            headers: {
                'Content-Type': 'text/javascript; charset=utf-8'
            }
        };
        testClient.createLayergroup(noGeomMapConfig, options, function(err, res) {
            assert.ok(/^test\(/.test(res.body), "Body start expected callback name: " + res.body);
            assert.ok(/column.*does not exist/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it("query with no geometry field returns 400 status",  function(done){
        var noGeometrySqlMapConfig = testClient.singleLayerMapConfig('SELECT 1');
        testClient.createLayergroup(noGeometrySqlMapConfig, { statusCode: 400 }, function(err, res) {
            assert.ok(/column.*does not exist/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it("bogus style should raise 400 status",  function(done){
        var bogusStyleMapConfig = testClient.defaultTableMapConfig('test_table', '#test_table{xxxxx;}');
        testClient.createLayergroup(bogusStyleMapConfig, { method: 'GET', statusCode: 400 }, done);
    });

    var defaultErrorExpectedResponse = {
        status: 400,
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        }
    };

    it('should raise 400 error for out of bounds layer index',  function(done){
        var mapConfig = testClient.singleLayerMapConfig('select * from test_table', null, null, 'name');

        testClient.getGrid(mapConfig, 1, 13, 4011, 3088, defaultErrorExpectedResponse, function(err, res) {
            assert.deepEqual(JSON.parse(res.body), { errors: ["Layer '1' not found in layergroup"] });
            done();
        });
    });

    it('error 400 on json syntax error', function(done) {
        var layergroup =  {
            version: '1.0.1',
            layers: [
                {
                    options: {
                        sql: 'select the_geom from test_table limit 1',
                        cartocss: '#layer { marker-fill:red }'
                    }
                }
            ]
        };
        assert.response(server,
            {
                url: '/database/windshaft_test/layergroup',
                method: 'POST',
                headers: {'Content-Type': 'application/json; charset=utf-8' },
                data: '{' + JSON.stringify(layergroup)
            },
            {
                status: 400
            },
            function(res) {
                var parsedBody = JSON.parse(res.body);
                assert.deepEqual(parsedBody, { errors: ['SyntaxError: Unexpected token {'] });
                done();
            }
        );
    });

});
<commit_msg>Rewrite tests to use new test client<commit_after>require('../support/test_helper');

var assert = require('../support/assert');
var Windshaft = require('../../lib/windshaft');
var ServerOptions = require('../support/server_options');
var OldTestClient = require('../support/test_client_old');
var TestClient = require('../support/test_client');

describe('multilayer error cases', function() {

    var server = new Windshaft.Server(ServerOptions);
    server.setMaxListeners(0);

    it("layergroup with no cartocss_version", function(done) {
      var layergroup =  {
        version: '1.0.0',
        layers: [
           { options: {
               sql: 'select cartodb_id, ST_Translate(the_geom, 50, 0) as the_geom from test_table limit 2',
               cartocss: '#layer { marker-fill:red; marker-width:32; marker-allow-overlap:true; }'
             } }
        ]
      };

        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, 'Missing cartocss_version for layer 0 options');
            done();
        });
    });

    it("sql/cartocss combination errors", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [{ options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer [missing=1] { line-width:16; }'
        }}]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(err.message.match(/column "missing" does not exist/m));
            // cannot check for error starting with style0 until a new enough mapnik
            // is used: https://github.com/mapnik/mapnik/issues/1924
            //assert.ok(error.match(/^style0/), "Error doesn't start with style0: " + error);
            // TODO: check which layer introduced the problem ?
            done();
        });
    });

    it("sql/interactivity combination error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }',
           interactivity: 'i'
          }},
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }'
          }},
          { options: {
           sql: "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#layer { line-width:16; }',
           interactivity: 'missing'
          }}
        ]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(err.message.match(/column "missing" does not exist/m));
            // TODO: check which layer introduced the problem ?
            done();
        });
    });

    it("blank CartoCSS error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style { line-width:16 }',
           interactivity: 'i'
          }},
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '',
           interactivity: 'i'
          }}
        ]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(err.message.match(/^style1: CartoCSS is empty/));
            done();
        });
    });

    it("Invalid mapnik-geometry-type CartoCSS error", function(done) {
      var layergroup =  {
        version: '1.0.1',
        layers: [
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }'
          }},
          { options: {
           sql: "select 1 as i, 'LINESTRING(0 0, 1 0)'::geometry as the_geom",
           cartocss_version: '2.0.2',
           cartocss: '#style [mapnik-geometry-type=bogus] { line-width:16 }'
          }}
        ]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            // carto-0.9.3 used to say "Failed to parse expression",
            // carto-0.9.5 says "not a valid keyword"
            assert.ok(err.message.match(/^style0:.*(Failed|not a valid)/));
            // TODO: check which layer introduced the problem ?
            done();
      });
    });

    it("post'ing style with non existent column in filter returns 400 with error", function(done) {
        var layergroup =  {
            version: '1.0.1',
            layers: [
                { options: {
                    sql: 'select * from test_table limit 1',
                    cartocss: '#test_table::outline[address="one"], [address="two"] { marker-fill: red; }',
                    cartocss_version: '2.0.2',
                    interactivity: [ 'cartodb_id' ]
                } },
                { options: {
                    sql: 'select * from test_big_poly limit 1',
                    cartocss: '#test_big_poly { marker-fill:blue }',
                    cartocss_version: '2.0.2',
                    interactivity: [ 'cartodb_id' ]
                } }
            ]
        };

        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(err.message.match(/column "address" does not exist/m));
            done();
        });
    });

    // See https://github.com/Vizzuality/Windshaft/issues/31
    it('bogus sql raises 400 status code', function(done) {
        var bogusSqlMapConfig = TestClient.singleLayerMapConfig('BOGUS FROM test_table');
        var testClient = new TestClient(bogusSqlMapConfig);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(/syntax error/.test(err.message), "Unexpected error: " + err.message);
            done();
        });
    });

    it('bogus sql raises 200 status code for jsonp', function(done) {
        var bogusSqlMapConfig = OldTestClient.singleLayerMapConfig('bogus');
        var options = {
            method: 'GET',
            callbackName: 'test',
            headers: {
                'Content-Type': 'text/javascript; charset=utf-8'
            }
        };
        OldTestClient.createLayergroup(bogusSqlMapConfig, options, function(err, res) {
            assert.ok(/^test\(/.test(res.body), "Body start expected callback name: " + res.body);
            assert.ok(/syntax error/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it('query not selecting the_geom raises 200 status code for jsonp instead of 404', function(done) {
        var noGeomMapConfig = OldTestClient.singleLayerMapConfig('select null::geometry the_geom_wadus');
        var options = {
            method: 'GET',
            callbackName: 'test',
            headers: {
                'Content-Type': 'text/javascript; charset=utf-8'
            }
        };
        OldTestClient.createLayergroup(noGeomMapConfig, options, function(err, res) {
            assert.ok(/^test\(/.test(res.body), "Body start expected callback name: " + res.body);
            assert.ok(/column.*does not exist/.test(res.body), "Unexpected error: " + res.body);
            done();
        });
    });

    it("query with no geometry field returns 400 status",  function(done){
        var noGeometrySqlMapConfig = TestClient.singleLayerMapConfig('SELECT 1');
        var testClient = new TestClient(noGeometrySqlMapConfig);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.ok(/column.*does not exist/.test(err.message), "Unexpected error: " + err.message);
            done();
        });
    });

    it("bogus style should raise 400 status",  function(done){
        var bogusStyleMapConfig = TestClient.defaultTableMapConfig('test_table', '#test_table{xxxxx;}');
        var testClient = new TestClient(bogusStyleMapConfig);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, 'style0:1:9 Invalid code: xxxxx;');
            done();
        });
    });

    it('should raise 400 error for out of bounds layer index',  function(done){
        var mapConfig = TestClient.singleLayerMapConfig('select * from test_table', null, null, 'name');
        var testClient = new TestClient(mapConfig);
        testClient.getTile(13, 4011, 3088, {layer: 1, format: 'grid.json'}, function(err) {
            assert.ok(err);
            assert.equal(err.message, "Layer '1' not found in layergroup");
            done();
        });
    });

    it('error 400 on json syntax error', function(done) {
        var layergroup =  {
            version: '1.0.1',
            layers: [
                {
                    options: {
                        sql: 'select the_geom from test_table limit 1',
                        cartocss: '#layer { marker-fill:red }'
                    }
                }
            ]
        };
        assert.response(server,
            {
                url: '/database/windshaft_test/layergroup',
                method: 'POST',
                headers: {'Content-Type': 'application/json; charset=utf-8' },
                data: '{' + JSON.stringify(layergroup)
            },
            {
                status: 400
            },
            function(res) {
                var parsedBody = JSON.parse(res.body);
                assert.deepEqual(parsedBody, { errors: ['SyntaxError: Unexpected token {'] });
                done();
            }
        );
    });

});
<|endoftext|>


<commit_before>import React from 'react'
import niceStyles from 'motion-nice-styles'
import { StyleSheet, css } from 'aphrodite'

export default function Style(ComposedComponent) {
  class StyledComponent extends ComposedComponent {
    constructor() {
      super(...arguments)

      if (this.style) {
        const styles = Object.assign({}, this.style)

        for (let style in styles)
          niceStyles(styles[style])

        this.stylesheet = StyleSheet.create(styles)
      }
    }

    render() {
      return this.stylesheet ?
        this.styleAll.call(this, super.render()) :
        super.render()
    }

    styleAll(children) {
      if (!children || !Array.isArray(children) && !children.props || !this.style)
        return children

      const count = React.Children.count(children)
      const styler = this.styleOne.bind(this)

      if (Array.isArray(children))
        return children.map(styler)
      if (count > 1)
        return React.Children.map(children, styler)
      else
        return styler(children)
    }

    styleOne(child) {
      if (Array.isArray(child))
        return this.styleAll(child)

      if (!child || !React.isValidElement(child))
        return child

      // <View /> + <tag /> keys
      const name = child.type && (child.type.name || child.type)

      // <name $tag /> keys
      const tagged = Object.keys(child.props)
        .filter(key => key[0] == '$' && child.props[key] === true) // only $props
        .map(key => key.slice(1)) // remove $

      // styles
      const styles = [name, ...tagged]
        .map(i => this.stylesheet[i])
        .reduce((acc, cur) => acc.concat(cur || []), [])

      let cloneProps = {}

      if (styles.length)
        cloneProps.className = css(...styles)

      if (child.props) {
        if (child.props.children)
          cloneProps.children = this.styleAll(child.props.children)
      }

      return React.cloneElement(child, cloneProps)
    }
  }

  return StyledComponent
}
<commit_msg>:art: linting and style in motion-style<commit_after>import React from 'react'
import niceStyles from 'motion-nice-styles'
import { StyleSheet, css } from 'aphrodite'

export default function Style(ComposedComponent) {
  class StyledComponent extends ComposedComponent {
    constructor() {
      super(...arguments)

      if (this.style) {
        const styles = Object.assign({}, this.style)

        for (const style in styles) {
          if (style) niceStyles(styles[style])
        }

        this.stylesheet = StyleSheet.create(styles)
      }
    }

    render() {
      return this.stylesheet ?
        this.styleAll.call(this, super.render()) :
        super.render()
    }

    styleAll(children) {
      if (!children || !Array.isArray(children) && !children.props || !this.style) return children

      const styler = this.styleOne.bind(this)
      if (Array.isArray(children)) return children.map(styler)

      const count = React.Children.count(children)
      if (count > 1) return React.Children.map(children, styler)
      return styler(children)
    }

    styleOne(child) {
      if (Array.isArray(child)) return this.styleAll(child)
      if (!child || !React.isValidElement(child)) return child

      // <View /> + <tag /> keys
      const name = child.type && (child.type.name || child.type)

      // <name $tag /> keys
      const tagged = Object.keys(child.props)
        .filter(key => key[0] === '$' && child.props[key] === true) // only $props
        .map(key => key.slice(1)) // remove $

      // styles
      const styles = [name, ...tagged]
        .map(i => this.stylesheet[i])
        .reduce((acc, cur) => acc.concat(cur || []), [])

      const cloneProps = {}
      if (styles.length) cloneProps.className = css(...styles)
      if (child.props && child.props.children) cloneProps.children = this.styleAll(child.props.children)

      return React.cloneElement(child, cloneProps)
    }
  }

  return StyledComponent
}
<|endoftext|>


<commit_before>/*jslint node:true,bitwise:true*/
/*globals Uint8Array, beforeEach, afterEach, it, expect, jasmine */
var testUtil = require('../../util');
var PromiseCompat = require('es6-promise').Promise;

module.exports = function (provider, setup) {
  'use strict';
  var socket, dispatch;

  beforeEach(function () {
    setup();
    dispatch = testUtil.createTestPort('msgs');
    socket = new provider.provider(undefined, dispatch.onMessage.bind(dispatch));
  });

  function rawStringToBuffer(str) {
    var idx, len = str.length, arr = [];
    for (idx = 0; idx < len; idx += 1) {
      arr[idx] = str.charCodeAt(idx) & 0xFF;
    }
    return new Uint8Array(arr).buffer;
  }

  it("Works as a Client", function (done) {
    socket.connect('www.google.com', 80, function () {
      var written = false;
      socket.write(rawStringToBuffer('GET / HTTP/1.0\n\n'), function (okay) {
        written = true;
      });
      dispatch.gotMessageAsync('onData', [], function (msg) {
        expect(written).toEqual(true);
        expect(dispatch.gotMessage('onData', [])).not.toEqual(false);
        socket.close(done);
      });
    });
  });

  it("Closes socket and open new one on the same port", function (done) {
    socket.listen('127.0.0.1', 9981, function () {
      socket.close(function () {
        socket.listen('127.0.0.1', 9981, function () {
          expect(true).toEqual(true);
          socket.close(done);
        });
      });
    });
  });

  it("Gets info on client & server sockets", function (done) {
    var cspy = jasmine.createSpy('client'),
        client,
        onConnect = function () {
          client.getInfo(function (info) {
            expect(info.localPort).toBeGreaterThan(1023);
            PromiseCompat.all([
              client.close(function () {}),
              socket.close(function () {}),
              done()]);
          });
        };

    socket.getInfo(function (info) {
      expect(info.connected).toEqual(false);
      expect(info.localPort).not.toBeDefined();
    });
    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        expect(info.localPort).toBeGreaterThan(1023);
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, onConnect);
      });
    });
  });

  it("Sends from Client to Server, onConnection/onDisconnect", function (done) {
    var cspy = jasmine.createSpy('client'),
        client,
        receiver,
        onDispatch,
        onConnect,
        onConnectionReceived;

    onDispatch = function (evt, msg) {
      if (evt === 'onDisconnect') {
        return;
      }
      expect(evt).toEqual('onData');
      expect(msg.data.byteLength).toEqual(10);
      PromiseCompat.all([ client.close(function () {}),
                          socket.close(function () {}) ]);
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      onConnectionReceived = true;
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
    });
    dispatch.gotMessageAsync('onDisconnect', [], function (msg) {
      expect(onConnectionReceived).toEqual(true);
      PromiseCompat.all([ receiver.close(function () {}),
                          done() ]);
    });
    onConnect = function () {
      var buf = new Uint8Array(10);
      client.write(buf.buffer, function () {});
    };
    socket.listen('127.0.0.1', 9981, function () {
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, onConnect);
    });
  });

  it("Pauses and resumes", function (done) {
    socket.connect('www.google.com', 80, function () {
      var paused = false;
      var closed = false;
      var pausedMessageCount = 0;
      dispatch.on('onMessage', function (msg) {
        if (!msg || !(msg.hasOwnProperty('data'))) {
          // Not an 'onData' message.
          return;
        }

        // One onData is allowed during pause due to https://crbug.com/360026
        if (paused && ++pausedMessageCount === 1) {
          return;
        }

        // Apart from the above exception, check that data doesn't arrive until
        // after the socket resumes.
        expect(paused).toEqual(false);

        if (!closed) {
          closed = true;
          socket.close(done);
        }
      });

      socket.pause(function () {
        paused = true;
        // This URL is selected to be a file large enough to generate
        // multiple onData events.
        socket.write(
          rawStringToBuffer('GET /images/srpr/logo11w.png HTTP/1.0\n\n'),
          function (okay) {});

        // Wait a second before unpausing.  Data received in this second
        // will fail the expectation that paused is false in gotMessageAsync.
        setTimeout(function () {
          // The observed behavior is that the next packet is received after
          // the call to resume, but before resume returns.
          socket.resume(function () {});
          paused = false;
        }, 1000);
      });
    });
  });

  it("Secures a socket", function (done) {
    socket.prepareSecure(function(success, err) {
      expect(err).toBeUndefined();
      socket.connect('www.google.com', 443, function (success, err) {
        expect(err).toBeUndefined();
        socket.secure(function(success, err) {
          expect(err).toBeUndefined();
          socket.getInfo(function (info) {
            expect(info.connected).toEqual(true);
            PromiseCompat.all([socket.close(function () {}),
                               done()]);
          });
        });
      });
    });
  });

  it("Gives error when securing a disconnected socket", function(done) {
    socket.secure(function (success, err) {
      expect(err.errcode).toEqual('NOT_CONNECTED');
      done();
    });
  });

  it("Gives error when connecting to invalid domain", function (done) {
    // Some ISPs (e.g. Time Warner) hijack all failed domains, so we use
    // a failing subdomain on a real domain.
    socket.connect('nosuchdomain.google.com', 80,
                   function (success, err) {
                     var allowedErrors = ['CONNECTION_FAILED',
                                          'NAME_NOT_RESOLVED'];
                     expect(allowedErrors).toContain(err.errcode);
                     done();
                   });
  });

  it("Gives error when writing a disconnected socket", function(done) {
    socket.write(rawStringToBuffer(''), function (success, err) {
      expect(err.errcode).toEqual('NOT_CONNECTED');
      done();
    });
  });

  it("Gives error when closing a disconnected socket", function(done) {
    socket.close(function (success, err) {
      expect(err.errcode).toEqual('SOCKET_CLOSED');
      done();
    });
  });

  it("Gives error when listening on already allocated socket", function(done) {
    socket.listen('127.0.0.1', 9981, function () {
      socket.listen('127.0.0.1', 9981, function (success, err) {
        expect(err.errcode).toEqual('ALREADY_CONNECTED');
        PromiseCompat.resolve(socket.close(done));
      });
    });
  });

  it("Socket reusing id of closed socket is also closed", function(done) {
    var cspy = jasmine.createSpy('client'),
        client,
        clientCopy;

    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      client.close(function () {
        clientCopy = new provider.provider(undefined, function () {},
                                           msg.socket);
        clientCopy.getInfo(function (info) {
          // TODO consider changing implementation to give more explicit failure
          expect(info.connected).toEqual(false);
          done();
        });
      });
    });
    socket.listen('127.0.0.1', 9981, function () {
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, function () {});
    });

  });

  // Tests that the sockets passed to server sockets' onConnection events
  // correctly dispatch onDisconnect events.
  //
  // Note that this also implicitly tests the close() method of client sockets.
  it("onConnection sockets dispatch onDisconnect", function(done) {
    var cspy = jasmine.createSpy('client'),
        client,
        receiver;
    var onDispatch = function (evt, msg) {
      expect(evt).toEqual('onDisconnect');
      socket.close(function () { receiver.close(function () { done() })});
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
      client.close(function () {});
    });

    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, function () {});
      });
    });
  });
};
<commit_msg>tcp disconnect test only close once for firefox<commit_after>/*jslint node:true,bitwise:true*/
/*globals Uint8Array, beforeEach, afterEach, it, expect, jasmine */
var testUtil = require('../../util');
var PromiseCompat = require('es6-promise').Promise;

module.exports = function (provider, setup) {
  'use strict';
  var socket, dispatch;

  beforeEach(function () {
    setup();
    dispatch = testUtil.createTestPort('msgs');
    socket = new provider.provider(undefined, dispatch.onMessage.bind(dispatch));
  });

  function rawStringToBuffer(str) {
    var idx, len = str.length, arr = [];
    for (idx = 0; idx < len; idx += 1) {
      arr[idx] = str.charCodeAt(idx) & 0xFF;
    }
    return new Uint8Array(arr).buffer;
  }

  it("Works as a Client", function (done) {
    socket.connect('www.google.com', 80, function () {
      var written = false;
      socket.write(rawStringToBuffer('GET / HTTP/1.0\n\n'), function (okay) {
        written = true;
      });
      dispatch.gotMessageAsync('onData', [], function (msg) {
        expect(written).toEqual(true);
        expect(dispatch.gotMessage('onData', [])).not.toEqual(false);
        socket.close(done);
      });
    });
  });

  it("Closes socket and open new one on the same port", function (done) {
    socket.listen('127.0.0.1', 9981, function () {
      socket.close(function () {
        socket.listen('127.0.0.1', 9981, function () {
          expect(true).toEqual(true);
          socket.close(done);
        });
      });
    });
  });

  it("Gets info on client & server sockets", function (done) {
    var cspy = jasmine.createSpy('client'),
        client,
        onConnect = function () {
          client.getInfo(function (info) {
            expect(info.localPort).toBeGreaterThan(1023);
            PromiseCompat.all([
              client.close(function () {}),
              socket.close(function () {}),
              done()]);
          });
        };

    socket.getInfo(function (info) {
      expect(info.connected).toEqual(false);
      expect(info.localPort).not.toBeDefined();
    });
    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        expect(info.localPort).toBeGreaterThan(1023);
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, onConnect);
      });
    });
  });

  it("Sends from Client to Server, onConnection/onDisconnect", function (done) {
    var cspy = jasmine.createSpy('client'),
        client,
        receiver,
        onDispatch,
        onConnect,
        onConnectionReceived;

    onDispatch = function (evt, msg) {
      if (evt === 'onDisconnect') {
        return;
      }
      expect(evt).toEqual('onData');
      expect(msg.data.byteLength).toEqual(10);
      PromiseCompat.all([ client.close(function () {}),
                          socket.close(function () {}) ]);
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      onConnectionReceived = true;
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
    });
    dispatch.gotMessageAsync('onDisconnect', [], function (msg) {
      expect(onConnectionReceived).toEqual(true);
      PromiseCompat.all([ receiver.close(function () {}),
                          done() ]);
    });
    onConnect = function () {
      var buf = new Uint8Array(10);
      client.write(buf.buffer, function () {});
    };
    socket.listen('127.0.0.1', 9981, function () {
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, onConnect);
    });
  });

  it("Pauses and resumes", function (done) {
    socket.connect('www.google.com', 80, function () {
      var paused = false;
      var closed = false;
      var pausedMessageCount = 0;
      dispatch.on('onMessage', function (msg) {
        if (!msg || !(msg.hasOwnProperty('data'))) {
          // Not an 'onData' message.
          return;
        }

        // One onData is allowed during pause due to https://crbug.com/360026
        if (paused && ++pausedMessageCount === 1) {
          return;
        }

        // Apart from the above exception, check that data doesn't arrive until
        // after the socket resumes.
        expect(paused).toEqual(false);

        if (!closed) {
          closed = true;
          socket.close(done);
        }
      });

      socket.pause(function () {
        paused = true;
        // This URL is selected to be a file large enough to generate
        // multiple onData events.
        socket.write(
          rawStringToBuffer('GET /images/srpr/logo11w.png HTTP/1.0\n\n'),
          function (okay) {});

        // Wait a second before unpausing.  Data received in this second
        // will fail the expectation that paused is false in gotMessageAsync.
        setTimeout(function () {
          // The observed behavior is that the next packet is received after
          // the call to resume, but before resume returns.
          socket.resume(function () {});
          paused = false;
        }, 1000);
      });
    });
  });

  it("Secures a socket", function (done) {
    socket.prepareSecure(function(success, err) {
      expect(err).toBeUndefined();
      socket.connect('www.google.com', 443, function (success, err) {
        expect(err).toBeUndefined();
        socket.secure(function(success, err) {
          expect(err).toBeUndefined();
          socket.getInfo(function (info) {
            expect(info.connected).toEqual(true);
            PromiseCompat.all([socket.close(function () {}),
                               done()]);
          });
        });
      });
    });
  });

  it("Gives error when securing a disconnected socket", function(done) {
    socket.secure(function (success, err) {
      expect(err.errcode).toEqual('NOT_CONNECTED');
      done();
    });
  });

  it("Gives error when connecting to invalid domain", function (done) {
    // Some ISPs (e.g. Time Warner) hijack all failed domains, so we use
    // a failing subdomain on a real domain.
    socket.connect('nosuchdomain.google.com', 80,
                   function (success, err) {
                     var allowedErrors = ['CONNECTION_FAILED',
                                          'NAME_NOT_RESOLVED'];
                     expect(allowedErrors).toContain(err.errcode);
                     done();
                   });
  });

  it("Gives error when writing a disconnected socket", function(done) {
    socket.write(rawStringToBuffer(''), function (success, err) {
      expect(err.errcode).toEqual('NOT_CONNECTED');
      done();
    });
  });

  it("Gives error when closing a disconnected socket", function(done) {
    socket.close(function (success, err) {
      expect(err.errcode).toEqual('SOCKET_CLOSED');
      done();
    });
  });

  it("Gives error when listening on already allocated socket", function(done) {
    socket.listen('127.0.0.1', 9981, function () {
      socket.listen('127.0.0.1', 9981, function (success, err) {
        expect(err.errcode).toEqual('ALREADY_CONNECTED');
        PromiseCompat.resolve(socket.close(done));
      });
    });
  });

  it("Socket reusing id of closed socket is also closed", function(done) {
    var cspy = jasmine.createSpy('client'),
        client,
        clientCopy;

    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      client.close(function () {
        clientCopy = new provider.provider(undefined, function () {},
                                           msg.socket);
        clientCopy.getInfo(function (info) {
          // TODO consider changing implementation to give more explicit failure
          expect(info.connected).toEqual(false);
          done();
        });
      });
    });
    socket.listen('127.0.0.1', 9981, function () {
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, function () {});
    });

  });

  // Tests that the sockets passed to server sockets' onConnection events
  // correctly dispatch onDisconnect events.
  //
  // Note that this also implicitly tests the close() method of client sockets.
  it("onConnection sockets dispatch onDisconnect", function(done) {
    var cspy = jasmine.createSpy('client'),
        client,
        receiver,
        received;
    var onDispatch = function (evt, msg) {
      if (!received) {
        received = true;
        expect(evt).toEqual('onDisconnect');
        socket.close(function () { receiver.close(function () { done() })});
      }
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      expect(msg.socket).toBeDefined();
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
      client.close(function () {});
    });

    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, function () {});
      });
    });
  });
};
<|endoftext|>


<commit_before>/**
 * Created by vcernomschi on 6/17/16.
 */

'use strict';

import GitHubApi from 'github';

export default class GitHubMsgPublisher {

  /**
   * @returns {string}
   * @constructor
   */
  static get isPullRequest() {
    let pullRequest = process.env['TRAVIS_PULL_REQUEST'];

    return (pullRequest !== 'false' || !isNaN(pullRequest));
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitPRNumber() {
    return process.env['TRAVIS_PULL_REQUEST'];
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitPrUrl() {
    return `https://api.github.com/repos/${GitHubMsgPublisher.gitUser}/${GitHubMsgPublisher.gitRepoName}/pulls/${GitHubMsgPublisher.gitPRNumber}`;
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitUser() {
    return process.env['TRAVIS_REPO_SLUG'].replace(/(.*)\/.*/i, '$1');
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitRepoName() {
    return process.env['TRAVIS_REPO_SLUG'].replace(/.*\/(.*)/i, '$1');
  }

  constructor() {
    this.github = new GitHubApi({
      debug: false,
      protocol: 'https',
      host: 'api.github.com',
      timeout: 5000,
      headers: {
        'user-agent': 'Code-Coverage-GitHub-App'
      },
      followRedirects: false, // default: true; there's currently an issue with non-get redirects, so allow ability to disable follow-redirects
      includePreview: true // default: false; includes accept headers to allow use of stuff under preview period
    });

    this.github.authenticate({
      type: 'oauth',
      token: process.env['GITHUB_OAUTH_TOKEN'],
    });
  }

  /**
   * Add comments for PR or fails if coverage
   * @param {Number} s3SumPercent - s3 summary coverage percent
   * @param {Number} localSumPercent - local summary coverage percent
   * @param {Function} callback
   */
  addComment(s3SumPercent, localSumPercent, callback) {
    let commentMsg;
    let isFailed = (localSumPercent < s3SumPercent);
    let failMsg = 'Failed due to decreasing coverage';

    //no need to add comments for !PR
    if (!GitHubMsgPublisher.isPullRequest) {
      callback(null, null);
      return;
    }

    if (isFailed) {
      commentMsg = `:x: coverage decreased from ${s3SumPercent}% to ${localSumPercent}%`;
    } else if (localSumPercent === s3SumPercent) {

      //use it when need to add comments for the same coverage
      //commentMsg = `:warning: coverage remained the same at ${localSumPercent}%`;
      console.log(`:warning: coverage remained the same at ${localSumPercent}%`);
      callback(null, null);
      return;
    } else {
      commentMsg = `:white_check_mark: coverage increased from ${s3SumPercent}% to ${localSumPercent}%`;
    }

    this.github.issues.getComments({
        user: GitHubMsgPublisher.gitUser,
        repo: GitHubMsgPublisher.gitRepoName,
        number: GitHubMsgPublisher.gitPRNumber,
      }, (err, issues) => {
        let isCommentAdded = false;

        if (err) {
          console.log(err);
          callback(err, null);
          return;
        }

        for (let issue of issues) {
          if (issue.hasOwnProperty('body') && issue.body === commentMsg) {
            isCommentAdded = true;
            console.log('Comment has already been added: ', commentMsg);

            if (isFailed) {
              console.log(failMsg);
              process.exit(1)
            }
          }
        }

        if (!isCommentAdded) {
          this.github.issues.createComment({
            user: GitHubMsgPublisher.gitUser,
            repo: GitHubMsgPublisher.gitRepoName,
            number: GitHubMsgPublisher.gitPRNumber,
            body: commentMsg,
          }, (err, res) => {
            if (err) {
              console.log(err);
              callback(err, null);
              return;
            }

            callback(null, res);

            if (isFailed) {
              console.log(failMsg);
              process.exit(1)
            }
          });
        }
      }
    );
  }
}
<commit_msg>Adjust script to fail build if coverage was decreased more that 1%<commit_after>/**
 * Created by vcernomschi on 6/17/16.
 */

'use strict';

import GitHubApi from 'github';

export default class GitHubMsgPublisher {

  /**
   * @returns {string}
   * @constructor
   */
  static get isPullRequest() {
    let pullRequest = process.env['TRAVIS_PULL_REQUEST'];

    return (pullRequest !== 'false' || !isNaN(pullRequest));
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitPRNumber() {
    return process.env['TRAVIS_PULL_REQUEST'];
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitPrUrl() {
    return `https://api.github.com/repos/${GitHubMsgPublisher.gitUser}/${GitHubMsgPublisher.gitRepoName}/pulls/${GitHubMsgPublisher.gitPRNumber}`;
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitUser() {
    return process.env['TRAVIS_REPO_SLUG'].replace(/(.*)\/.*/i, '$1');
  }

  /**
   * @returns {string}
   * @constructor
   */
  static get gitRepoName() {
    return process.env['TRAVIS_REPO_SLUG'].replace(/.*\/(.*)/i, '$1');
  }

  constructor() {
    this.github = new GitHubApi({
      debug: false,
      protocol: 'https',
      host: 'api.github.com',
      timeout: 5000,
      headers: {
        'user-agent': 'Code-Coverage-GitHub-App'
      },
      followRedirects: false, // default: true; there's currently an issue with non-get redirects, so allow ability to disable follow-redirects
      includePreview: true // default: false; includes accept headers to allow use of stuff under preview period
    });

    this.github.authenticate({
      type: 'oauth',
      token: process.env['GITHUB_OAUTH_TOKEN'],
    });
  }

  /**
   * Add comments for PR or fails if coverage
   * @param {Number} s3SumPercent - s3 summary coverage percent
   * @param {Number} localSumPercent - local summary coverage percent
   * @param {Function} callback
   */
  addComment(s3SumPercent, localSumPercent, callback) {
    let commentMsg;

    //failed if coverage decreased more that 1 %
    let isFailed = ((localSumPercent + 1) < s3SumPercent);
    let failMsg = 'Failed due to decreasing coverage';

    //no need to add comments for !PR
    if (!GitHubMsgPublisher.isPullRequest) {
      callback(null, null);
      return;
    }

    if (isFailed) {
      commentMsg = `:x: coverage decreased from ${s3SumPercent}% to ${localSumPercent}%`;
    } else if (localSumPercent === s3SumPercent) {

      //use it when need to add comments for the same coverage
      //commentMsg = `:warning: coverage remained the same at ${localSumPercent}%`;
      console.log(`:warning: coverage remained the same at ${localSumPercent}%`);
      callback(null, null);
      return;
    } else {
      commentMsg = `:white_check_mark: coverage increased from ${s3SumPercent}% to ${localSumPercent}%`;
    }

    this.github.issues.getComments({
        user: GitHubMsgPublisher.gitUser,
        repo: GitHubMsgPublisher.gitRepoName,
        number: GitHubMsgPublisher.gitPRNumber,
      }, (err, issues) => {
        let isCommentAdded = false;

        if (err) {
          console.log(err);
          callback(err, null);
          return;
        }

        for (let issue of issues) {
          if (issue.hasOwnProperty('body') && issue.body === commentMsg) {
            isCommentAdded = true;
            console.log('Comment has already been added: ', commentMsg);

            if (isFailed) {
              console.log(failMsg);
              process.exit(1)
            }
          }
        }

        if (!isCommentAdded) {
          this.github.issues.createComment({
            user: GitHubMsgPublisher.gitUser,
            repo: GitHubMsgPublisher.gitRepoName,
            number: GitHubMsgPublisher.gitPRNumber,
            body: commentMsg,
          }, (err, res) => {
            if (err) {
              console.log(err);
              callback(err, null);
              return;
            }

            callback(null, res);

            if (isFailed) {
              console.log(failMsg);
              process.exit(1)
            }
          });
        }
      }
    );
  }
}
<|endoftext|>


<commit_before>// Traverse the DOM tree in our spinoff of jQuery's closest()
function getClosest(el, divID)
{
	if (typeof divID == 'undefined' || divID == false)
		return null;

	do
	{
		// End the loop if quick edit is detected.
		if (el.nodeName === 'TEXTAREA' || el.nodeName === 'INPUT' || el.id === 'error_box')
			break;

		if (el.id === divID)
		{
			return el;
		}
	}
	while (el = el.parentNode);

	// not found :(
	return null;
}

function getSelectedText(divID)
{
	if (typeof divID == 'undefined' || divID == false)
		return false;

	var text = '',
	selection,
	found = 0;

	if (window.getSelection)
	{
		selection = window.getSelection();
		text = selection.toString();
	}
	else if (document.selection && document.selection.type != 'Control')
	{
		selection = document.selection.createRange();
		text = selection.text;
	}

	// Need to be sure the selected text does belong to the right div.
	for (var i = 0; i < selection.rangeCount; i++) {
			s = getClosest(selection.getRangeAt(i).startContainer, divID);
			e = getClosest(selection.getRangeAt(i).endContainer, divID);

			if (s !== null && e !== null)
			{
				found = 1;
				break;
			}
		}

	return found === 1 ? text : false;
}

function quotedTextClick(oOptions)
{
		text = '';

		// The process has been started, hide the button.
		$('#quoteSelected_' + oOptions.msgID).hide();

		// Do a call to make sure this is a valid message.
		$.ajax({
			url: smf_prepareScriptUrl(smf_scripturl) + 'action=quotefast;quote=' + oOptions.msgID + ';xml;pb='+ oEditorID + ';mode=' + (oEditorObject.bRichTextEnabled ? 1 : 0),
			type: 'GET',
			dataType: 'xml',
			beforeSend: function () {
				ajax_indicator(true);
			},
			success: function (data, textStatus, xhr) {
				// Search the xml data to get the quote tag.
				text = $(data).find('quote').text();

				// Insert the selected text between the quotes BBC tags.
				text = text.match(/^\[quote(.*)]/ig) + oOptions.text + '[/quote]' + '\n\n';

				// Add the whole text to the editor's instance.
				$('#' + oEditorID).data('sceditor').sourceEditorInsertText(text);

				// Move the view to the quick reply box. If available.
				if (typeof oJumpAnchor != 'undefined'){
					if (navigator.appName == 'Microsoft Internet Explorer')
						window.location.hash = oJumpAnchor;
					else
						window.location.hash = '#' + oJumpAnchor;
				}

				ajax_indicator(false);
			},
			error: function (xhr, textStatus, errorThrown) {
				ajax_indicator(false);
			}
		});
}

$(function() {

	// Event for handling selected quotes.
	$(document).on('mouseup', '.inner, .list_posts', function() {

		// Get everything we need.
		var oSelected = {
			divID : $(this).attr('id'),
			msgID : $(this).data('msgid'),
		};

		// If the button is already visible, hide it!
		$('#quoteSelected_' + oSelected.msgID).hide();

		// Get any selected text.
		oSelected.text = getSelectedText(oSelected.divID);

		// Do we have some selected text?
		if (typeof oSelected.text == 'undefined' || oSelected.text == false)
			return false;

		// Show the "quote this" button.
		$('#quoteSelected_' + oSelected.msgID).show();

			$(document).one('click', '#quoteSelected_' + oSelected.msgID + ' a', function(e){
				e.preventDefault();
				quotedTextClick(oSelected);
			});

		return false;
	});
});<commit_msg>WYSIWYG and quote selected fixes #3026<commit_after>// Traverse the DOM tree in our spinoff of jQuery's closest()
function getClosest(el, divID)
{
	if (typeof divID == 'undefined' || divID == false)
		return null;

	do
	{
		// End the loop if quick edit is detected.
		if (el.nodeName === 'TEXTAREA' || el.nodeName === 'INPUT' || el.id === 'error_box')
			break;

		if (el.id === divID)
		{
			return el;
		}
	}
	while (el = el.parentNode);

	// not found :(
	return null;
}

function getSelectedText(divID)
{
	if (typeof divID == 'undefined' || divID == false)
		return false;

	var text = '',
	selection,
	found = 0;

	if (window.getSelection)
	{
		selection = window.getSelection();
		text = selection.toString();
	}
	else if (document.selection && document.selection.type != 'Control')
	{
		selection = document.selection.createRange();
		text = selection.text;
	}

	// Need to be sure the selected text does belong to the right div.
	for (var i = 0; i < selection.rangeCount; i++) {
			s = getClosest(selection.getRangeAt(i).startContainer, divID);
			e = getClosest(selection.getRangeAt(i).endContainer, divID);

			if (s !== null && e !== null)
			{
				found = 1;
				break;
			}
		}

	return found === 1 ? text : false;
}

function quotedTextClick(oOptions)
{
		text = '';

		// The process has been started, hide the button.
		$('#quoteSelected_' + oOptions.msgID).hide();

		// Do a call to make sure this is a valid message.
		$.ajax({
			url: smf_prepareScriptUrl(smf_scripturl) + 'action=quotefast;quote=' + oOptions.msgID + ';xml;pb='+ oEditorID + ';mode=' + (oEditorObject.bRichTextEnabled ? 1 : 0),
			type: 'GET',
			dataType: 'xml',
			beforeSend: function () {
				ajax_indicator(true);
			},
			success: function (data, textStatus, xhr) {
				// Search the xml data to get the quote tag.
				text = $(data).find('quote').text();

				// Insert the selected text between the quotes BBC tags.
				text = text.match(/^\[quote(.*)]/ig) + oOptions.text + '[/quote]' + '\n\n';

				// Get the editor stuff.
				var oEditor = $('#' + oEditorID).data('sceditor');

				// Detect the mode.
				if (oEditor.inSourceMode()){
					oEditor.sourceEditorInsertText(text);
				}

				else{
					oEditor.wysiwygEditorInsertHtml(oEditor.fromBBCode(text));
				}

				// Move the view to the quick reply box. If available.
				if (typeof oJumpAnchor != 'undefined'){
					if (navigator.appName == 'Microsoft Internet Explorer')
						window.location.hash = oJumpAnchor;
					else
						window.location.hash = '#' + oJumpAnchor;
				}

				ajax_indicator(false);
			},
			error: function (xhr, textStatus, errorThrown) {
				ajax_indicator(false);
			}
		});
}

$(function() {

	// Event for handling selected quotes.
	$(document).on('mouseup', '.inner, .list_posts', function() {

		// Get everything we need.
		var oSelected = {
			divID : $(this).attr('id'),
			msgID : $(this).data('msgid'),
		};

		// If the button is already visible, hide it!
		$('#quoteSelected_' + oSelected.msgID).hide();

		// Get any selected text.
		oSelected.text = getSelectedText(oSelected.divID);

		// Do we have some selected text?
		if (typeof oSelected.text == 'undefined' || oSelected.text == false)
			return false;

		// Show the "quote this" button.
		$('#quoteSelected_' + oSelected.msgID).show();

			$(document).one('click', '#quoteSelected_' + oSelected.msgID + ' a', function(e){
				e.preventDefault();
				quotedTextClick(oSelected);
			});

		return false;
	});
});<|endoftext|>


<commit_before>exports.log = jsio.__env.log;
exports.GLOBAL = jsio.__env.global;

exports.bind = function(context, method /*, VARGS*/) {
	if(arguments.length > 2) {
		var args = Array.prototype.slice.call(arguments, 2);
		return typeof method == 'string'
			? function() {
				if (context[method]) {
					return context[method].apply(context, args.concat(Array.prototype.slice.call(arguments, 0)));
				} else {
					throw logger.error('No method:', method, 'for context', context);
				}
			}
			: function() { return method.apply(context, args.concat(Array.prototype.slice.call(arguments, 0))); }
	} else {
		return typeof method == 'string'
			? function() {
				if (context[method]) {
					return context[method].apply(context, arguments);
				} else {
					throw logger.error('No method:', method, 'for context', context);
				}
			}
			: function() { return method.apply(context, arguments); }
	}
}

exports.Class = function(parent, proto) {
	if(!parent) { throw new Error('parent or prototype not provided'); }
	if(!proto) { proto = parent; parent = null; }
	else if(parent instanceof Array) { // multiple inheritance, use at your own risk =)
		proto.prototype = {};
		for(var i = 0, p; p = parent[i]; ++i) {
			for(var item in p.prototype) {
				if(!(item in proto.prototype)) {
					proto.prototype[item] = p.prototype[item];
				}
			}
		}
		parent = parent[0];
	} else {
		proto.prototype = parent.prototype;
	}

	var cls = function() { if(this.init) { return this.init.apply(this, arguments); }}
	cls.prototype = new proto(parent ? function(context, method, args) {
		var args = args || [];
		var target = proto;
		while(target = target.prototype) {
			if(target[method]) {
				return target[method].apply(context, args);
			}
		}
		throw new Error('method ' + method + ' does not exist');
	} : null);
	cls.prototype.constructor = cls;
	return cls;
}

exports.$setTimeout = function(f, t/*, VARGS */) {
	var args = Array.prototype.slice.call(arguments, 2);
	return setTimeout(function() {
		try {
			f.apply(this, args);
		} catch(e) {
			// log?
		}
	}, t)
}

exports.$setInterval = function(f, t/*, VARGS */) {
	var args = Array.prototype.slice.call(arguments, 2);
	return setInterval(function() {
		try {
			f.apply(this, args);
		} catch(e) {
			// log?
		}
	}, t)
}

// node doesn't let you call clearTimeout(null)
exports.$clearTimeout = function (timer) { return timer ? clearTimeout(timer) : null; };
exports.$clearInterval = function (timer) { return timer ? clearInterval(timer) : null; };

// keep logging local variables out of other closures in this file!
exports.logging = (function() {

	// logging namespace, this is what is exported
	var logging = {
			DEBUG: 1,
			LOG: 2,
			INFO: 3,
			WARN: 4,
			ERROR: 5
		},
		loggers = {}, // effectively globals - all loggers and a global production state
		production = false;

	logging.setProduction = function(prod) { production = !!prod; }
	logging.get = function(name) {
		return loggers.hasOwnProperty(name) ? loggers[name]
			: (loggers[name] = new Logger(name));
	}
	logging.set = function(name, _logger) {
		loggers[name] = _logger;
	}

	logging.getAll = function() { return loggers; }

	logging.__create = function(pkg, ctx) { ctx.logger = logging.get(pkg); }

	var Logger = exports.Class(function() {
		this.init = function(name, level) {
			this._name = name;
			this._level = level || logging.LOG;
			this._listener = exports.log;
		}

		this.setLevel = function(level) { this._level = level; }

		var SLICE = Array.prototype.slice;

		function makeLogFunction(level, type) {
			return function() {
				if (!production && level >= this._level) {
					return this._listener.apply(this._listener, [type, this._name].concat(SLICE.call(arguments)));
				}
				return arguments[0];
			}
		}

		this.setListener = function(listener) { log = listener; }
		this.debug = makeLogFunction(logging.DEBUG, "DEBUG");
		this.log = makeLogFunction(logging.LOG, "LOG");
		this.info = makeLogFunction(logging.INFO, "INFO");
		this.warn = makeLogFunction(logging.WARN, "WARN");
		this.error = makeLogFunction(logging.ERROR, "ERROR");
	});

	return logging;
})();

var logger = exports.logging.get('jsiocore');
<commit_msg>move Array.prototype.slice to a variable at the top of base.js for more concise code in this module -- should not have any external effects<commit_after>exports.log = jsio.__env.log;
exports.GLOBAL = jsio.__env.global;

var SLICE = Array.prototype.slice;

exports.bind = function(context, method /*, VARGS*/) {
	if(arguments.length > 2) {
		var args = SLICE.call(arguments, 2);
		return typeof method == 'string'
			? function() {
				if (context[method]) {
					return context[method].apply(context, args.concat(SLICE.call(arguments, 0)));
				} else {
					throw logger.error('No method:', method, 'for context', context);
				}
			}
			: function() { return method.apply(context, args.concat(SLICE.call(arguments, 0))); }
	} else {
		return typeof method == 'string'
			? function() {
				if (context[method]) {
					return context[method].apply(context, arguments);
				} else {
					throw logger.error('No method:', method, 'for context', context);
				}
			}
			: function() { return method.apply(context, arguments); }
	}
}

exports.Class = function(parent, proto) {
	if(!parent) { throw new Error('parent or prototype not provided'); }
	if(!proto) { proto = parent; parent = null; }
	else if(parent instanceof Array) { // multiple inheritance, use at your own risk =)
		proto.prototype = {};
		for(var i = 0, p; p = parent[i]; ++i) {
			for(var item in p.prototype) {
				if(!(item in proto.prototype)) {
					proto.prototype[item] = p.prototype[item];
				}
			}
		}
		parent = parent[0];
	} else {
		proto.prototype = parent.prototype;
	}

	var cls = function() { if(this.init) { return this.init.apply(this, arguments); }}
	cls.prototype = new proto(parent ? function(context, method, args) {
		var args = args || [];
		var target = proto;
		while(target = target.prototype) {
			if(target[method]) {
				return target[method].apply(context, args);
			}
		}
		throw new Error('method ' + method + ' does not exist');
	} : null);
	cls.prototype.constructor = cls;
	return cls;
}

exports.$setTimeout = function(f, t/*, VARGS */) {
	var args = SLICE.call(arguments, 2);
	return setTimeout(function() {
		try {
			f.apply(this, args);
		} catch(e) {
			// log?
		}
	}, t)
}

exports.$setInterval = function(f, t/*, VARGS */) {
	var args = SLICE.call(arguments, 2);
	return setInterval(function() {
		try {
			f.apply(this, args);
		} catch(e) {
			// log?
		}
	}, t)
}

// node doesn't let you call clearTimeout(null)
exports.$clearTimeout = function (timer) { return timer ? clearTimeout(timer) : null; };
exports.$clearInterval = function (timer) { return timer ? clearInterval(timer) : null; };

// keep logging local variables out of other closures in this file!
exports.logging = (function() {

	// logging namespace, this is what is exported
	var logging = {
			DEBUG: 1,
			LOG: 2,
			INFO: 3,
			WARN: 4,
			ERROR: 5
		},
		loggers = {}, // effectively globals - all loggers and a global production state
		production = false;

	logging.setProduction = function(prod) { production = !!prod; }
	logging.get = function(name) {
		return loggers.hasOwnProperty(name) ? loggers[name]
			: (loggers[name] = new Logger(name));
	}
	logging.set = function(name, _logger) {
		loggers[name] = _logger;
	}

	logging.getAll = function() { return loggers; }

	logging.__create = function(pkg, ctx) { ctx.logger = logging.get(pkg); }

	var Logger = exports.Class(function() {
		this.init = function(name, level) {
			this._name = name;
			this._level = level || logging.LOG;
			this._listener = exports.log;
		}

		this.setLevel = function(level) { this._level = level; }

		function makeLogFunction(level, type) {
			return function() {
				if (!production && level >= this._level) {
					return this._listener.apply(this._listener, [type, this._name].concat(SLICE.call(arguments)));
				}
				return arguments[0];
			}
		}

		this.setListener = function(listener) { log = listener; }
		this.debug = makeLogFunction(logging.DEBUG, "DEBUG");
		this.log = makeLogFunction(logging.LOG, "LOG");
		this.info = makeLogFunction(logging.INFO, "INFO");
		this.warn = makeLogFunction(logging.WARN, "WARN");
		this.error = makeLogFunction(logging.ERROR, "ERROR");
	});

	return logging;
})();

var logger = exports.logging.get('jsiocore');
<|endoftext|>