<commit_before>import { Platform } from 'react-native';

const IS_ANDROID = Platform.OS === 'android';

// Get scroll interpolator's input range from an array of slide indexes
// Indexes are relative to the current active slide (index 0)
// For example, using [3, 2, 1, 0, -1] will return:
// [
//     (index - 3) * sizeRef, // active + 3
//     (index - 2) * sizeRef, // active + 2
//     (index - 1) * sizeRef, // active + 1
//     index * sizeRef, // active
//     (index + 1) * sizeRef // active - 1
// ]
export function getInputRangeFromIndexes (range, index, carouselProps) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    let inputRange = [];

    for (let i = 0; i < range.length; i++) {
        inputRange.push((index - range[i]) * sizeRef);
    }

    return inputRange;
}

// Default behavior
// Scale and/or opacity effect
// Based on props 'inactiveSlideOpacity' and 'inactiveSlideScale'
export function defaultScrollInterpolator (index, carouselProps) {
    const range = [1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = [0, 1, 0];

    return { inputRange, outputRange };
}
export function defaultAnimatedStyles (index, animatedValue, carouselProps) {
    let animatedOpacity = {};
    let animatedScale = {};

    if (carouselProps.inactiveSlideOpacity < 1) {
        animatedOpacity = {
            opacity: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideOpacity, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideScale < 1) {
        animatedScale = {
            transform: [{
                scale: animatedValue.interpolate({
                    inputRange: [0, 1],
                    outputRange: [carouselProps.inactiveSlideScale, 1]
                })
            }]
        };
    }

    return {
        ...animatedOpacity,
        ...animatedScale
    };
}

// Shift animation
// Same as the default one, but the active slide is also shifted up or down
// Based on prop 'inactiveSlideShift'
export function shiftAnimatedStyles (index, animatedValue, carouselProps) {
    let animatedOpacity = {};
    let animatedScale = {};
    let animatedTranslate = {};

    if (carouselProps.inactiveSlideOpacity < 1) {
        animatedOpacity = {
            opacity: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideOpacity, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideScale < 1) {
        animatedScale = {
            scale: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideScale, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideShift !== 0) {
        const translateProp = carouselProps.vertical ? 'translateX' : 'translateY';
        animatedTranslate = {
            [translateProp]: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideShift, 0]
            })
        };
    }

    return {
        ...animatedOpacity,
        transform: [
            { ...animatedScale },
            { ...animatedTranslate }
        ]
    };
}

// Stack animation
// Imitate a deck/stack of cards (see #195)
// WARNING: The effect had to be visually inverted on Android because this OS doesn't honor the `zIndex`property
// This means that the item with the higher zIndex (and therefore the tap receiver) remains the one AFTER the currently active item
// The `elevation` property compensates for that only visually, which is not good enough
export function stackScrollInterpolator (index, carouselProps) {
    const range = IS_ANDROID ?
        [1, 0, -1, -2, -3] :
        [3, 2, 1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = range;

    return { inputRange, outputRange };
}
export function stackAnimatedStyles (index, animatedValue, carouselProps, cardOffset) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    const translateProp = carouselProps.vertical ? 'translateY' : 'translateX';

    const card1Scale = 0.9;
    const card2Scale = 0.8;

    cardOffset = !cardOffset && cardOffset !== 0 ? 18 : cardOffset;

    const getTranslateFromScale = (index, scale) => {
        const centerFactor = 1 / scale * index;
        const centeredPosition = -Math.round(sizeRef * centerFactor);
        const edgeAlignment = Math.round((sizeRef - (sizeRef * scale)) / 2);
        const offset = Math.round(cardOffset * Math.abs(index) / scale);

        return IS_ANDROID ?
            centeredPosition - edgeAlignment - offset :
            centeredPosition + edgeAlignment + offset;
    };

    return IS_ANDROID ? {
        zIndex: carouselProps.data.length - index,
        // elevation: carouselProps.data.length - index, // fix zIndex bug visually, but not from a logic point of view
        opacity: animatedValue.interpolate({
            inputRange: [-3, -2, -1, 0],
            outputRange: [0, 0.5, 0.75, 1],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-2, -1, 0, 1],
                outputRange: [card2Scale, card1Scale, 1, card1Scale],
                extrapolate: 'clamp'
            })
        }, {
            [translateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0, 1],
                outputRange: [
                    getTranslateFromScale(-3, card2Scale),
                    getTranslateFromScale(-2, card2Scale),
                    getTranslateFromScale(-1, card1Scale),
                    0,
                    sizeRef * 0.5
                ],
                extrapolate: 'clamp'
            })
        }]
    } : {
        zIndex: carouselProps.data.length - index,
        opacity: animatedValue.interpolate({
            inputRange: [0, 1, 2, 3],
            outputRange: [1, 0.75, 0.5, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2],
                outputRange: [card1Scale, 1, card1Scale, card2Scale],
                extrapolate: 'clamp'
            })
        }, {
            [translateProp]: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2, 3],
                outputRange: [
                    -sizeRef * 0.5,
                    0,
                    getTranslateFromScale(1, card1Scale),
                    getTranslateFromScale(2, card2Scale),
                    getTranslateFromScale(3, card2Scale)
                ],
                extrapolate: 'clamp'
            })
        }]
    };
}

// Tinder animation
// Imitate the popular Tinder layout
// WARNING: The effect had to be visually inverted on Android because this OS doesn't honor the `zIndex`property
// This means that the item with the higher zIndex (and therefore the tap receiver) remains the one AFTER the currently active item
// The `elevation` property compensates for that only visually, which is not good enough
export function tinderScrollInterpolator (index, carouselProps) {
    const range = IS_ANDROID ?
        [1, 0, -1, -2, -3] :
        [3, 2, 1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = range;

    return { inputRange, outputRange };
}
export function tinderAnimatedStyles (index, animatedValue, carouselProps, cardOffset) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    const mainTranslateProp = carouselProps.vertical ? 'translateY' : 'translateX';
    const secondaryTranslateProp = carouselProps.vertical ? 'translateX' : 'translateY';

    const card1Scale = 0.96;
    const card2Scale = 0.92;
    const card3Scale = 0.88;

    const peekingCardsOpacity = IS_ANDROID ? 0.92 : 1;

    cardOffset = !cardOffset && cardOffset !== 0 ? 9 : cardOffset;

    const getMainTranslateFromScale = (index, scale) => {
        const centerFactor = 1 / scale * index;
        return -Math.round(sizeRef * centerFactor);
    };

    const getSecondaryTranslateFromScale = (index, scale) => {
        return Math.round(cardOffset * Math.abs(index) / scale);
    };

    return IS_ANDROID ? {
        zIndex: carouselProps.data.length - index,
        // elevation: carouselProps.data.length - index, // fix zIndex bug visually, but not from a logic point of view
        opacity: animatedValue.interpolate({
            inputRange: [-3, -2, -1, 0, 1],
            outputRange: [0, peekingCardsOpacity, peekingCardsOpacity, 1, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0],
                outputRange: [card3Scale, card2Scale, card1Scale, 1],
                extrapolate: 'clamp'
            })
        }, {
            rotate: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: ['0deg', '22deg'],
                extrapolate: 'clamp'
            })
        }, {
            [mainTranslateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0, 1],
                outputRange: [
                    getMainTranslateFromScale(-3, card3Scale),
                    getMainTranslateFromScale(-2, card2Scale),
                    getMainTranslateFromScale(-1, card1Scale),
                    0,
                    sizeRef * 1.1
                ],
                extrapolate: 'clamp'
            })
        }, {
            [secondaryTranslateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0],
                outputRange: [
                    getSecondaryTranslateFromScale(-3, card3Scale),
                    getSecondaryTranslateFromScale(-2, card2Scale),
                    getSecondaryTranslateFromScale(-1, card1Scale),
                    0
                ],
                extrapolate: 'clamp'
            })
        }]
    } : {
        zIndex: carouselProps.data.length - index,
        opacity: animatedValue.interpolate({
            inputRange: [-1, 0, 1, 2, 3],
            outputRange: [0, 1, peekingCardsOpacity, peekingCardsOpacity, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [0, 1, 2, 3],
                outputRange: [1, card1Scale, card2Scale, card3Scale],
                extrapolate: 'clamp'
            })
        }, {
            rotate: animatedValue.interpolate({
                inputRange: [-1, 0],
                outputRange: ['-22deg', '0deg'],
                extrapolate: 'clamp'
            })
        }, {
            [mainTranslateProp]: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2, 3],
                outputRange: [
                    -sizeRef * 1.1,
                    0,
                    getMainTranslateFromScale(1, card1Scale),
                    getMainTranslateFromScale(2, card2Scale),
                    getMainTranslateFromScale(3, card3Scale)
                ],
                extrapolate: 'clamp'
            })
        }, {
            [secondaryTranslateProp]: animatedValue.interpolate({
                inputRange: [0, 1, 2, 3],
                outputRange: [
                    0,
                    getSecondaryTranslateFromScale(1, card1Scale),
                    getSecondaryTranslateFromScale(2, card2Scale),
                    getSecondaryTranslateFromScale(3, card3Scale)
                ],
                extrapolate: 'clamp'
            })
        }]
    };
}
<commit_msg>refactor(animations): minor update<commit_after>import { Platform } from 'react-native';

const IS_ANDROID = Platform.OS === 'android';

// Get scroll interpolator's input range from an array of slide indexes
// Indexes are relative to the current active slide (index 0)
// For example, using [3, 2, 1, 0, -1] will return:
// [
//     (index - 3) * sizeRef, // active + 3
//     (index - 2) * sizeRef, // active + 2
//     (index - 1) * sizeRef, // active + 1
//     index * sizeRef, // active
//     (index + 1) * sizeRef // active - 1
// ]
export function getInputRangeFromIndexes (range, index, carouselProps) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    let inputRange = [];

    for (let i = 0; i < range.length; i++) {
        inputRange.push((index - range[i]) * sizeRef);
    }

    return inputRange;
}

// Default behavior
// Scale and/or opacity effect
// Based on props 'inactiveSlideOpacity' and 'inactiveSlideScale'
export function defaultScrollInterpolator (index, carouselProps) {
    const range = [1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = [0, 1, 0];

    return { inputRange, outputRange };
}
export function defaultAnimatedStyles (index, animatedValue, carouselProps) {
    let animatedOpacity = {};
    let animatedScale = {};

    if (carouselProps.inactiveSlideOpacity < 1) {
        animatedOpacity = {
            opacity: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideOpacity, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideScale < 1) {
        animatedScale = {
            transform: [{
                scale: animatedValue.interpolate({
                    inputRange: [0, 1],
                    outputRange: [carouselProps.inactiveSlideScale, 1]
                })
            }]
        };
    }

    return {
        ...animatedOpacity,
        ...animatedScale
    };
}

// Shift animation
// Same as the default one, but the active slide is also shifted up or down
// Based on prop 'inactiveSlideShift'
export function shiftAnimatedStyles (index, animatedValue, carouselProps) {
    let animatedOpacity = {};
    let animatedScale = {};
    let animatedTranslate = {};

    if (carouselProps.inactiveSlideOpacity < 1) {
        animatedOpacity = {
            opacity: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideOpacity, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideScale < 1) {
        animatedScale = {
            scale: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideScale, 1]
            })
        };
    }

    if (carouselProps.inactiveSlideShift !== 0) {
        const translateProp = carouselProps.vertical ? 'translateX' : 'translateY';
        animatedTranslate = {
            [translateProp]: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: [carouselProps.inactiveSlideShift, 0]
            })
        };
    }

    return {
        ...animatedOpacity,
        transform: [
            { ...animatedScale },
            { ...animatedTranslate }
        ]
    };
}

// Stack animation
// Imitate a deck/stack of cards (see #195)
// WARNING: The effect had to be visually inverted on Android because this OS doesn't honor the `zIndex`property
// This means that the item with the higher zIndex (and therefore the tap receiver) remains the one AFTER the currently active item
// The `elevation` property compensates for that only visually, which is not good enough
export function stackScrollInterpolator (index, carouselProps) {
    const range = IS_ANDROID ?
        [1, 0, -1, -2, -3] :
        [3, 2, 1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = range;

    return { inputRange, outputRange };
}
export function stackAnimatedStyles (index, animatedValue, carouselProps, cardOffset) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    const translateProp = carouselProps.vertical ? 'translateY' : 'translateX';

    const card1Scale = 0.9;
    const card2Scale = 0.8;

    cardOffset = !cardOffset && cardOffset !== 0 ? 18 : cardOffset;

    const getTranslateFromScale = (cardIndex, scale) => {
        const centerFactor = 1 / scale * cardIndex;
        const centeredPosition = -Math.round(sizeRef * centerFactor);
        const edgeAlignment = Math.round((sizeRef - (sizeRef * scale)) / 2);
        const offset = Math.round(cardOffset * Math.abs(cardIndex) / scale);

        return IS_ANDROID ?
            centeredPosition - edgeAlignment - offset :
            centeredPosition + edgeAlignment + offset;
    };

    return IS_ANDROID ? {
        // elevation: carouselProps.data.length - index, // fix zIndex bug visually, but not from a logic point of view
        opacity: animatedValue.interpolate({
            inputRange: [-3, -2, -1, 0],
            outputRange: [0, 0.5, 0.75, 1],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-2, -1, 0, 1],
                outputRange: [card2Scale, card1Scale, 1, card1Scale],
                extrapolate: 'clamp'
            })
        }, {
            [translateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0, 1],
                outputRange: [
                    getTranslateFromScale(-3, card2Scale),
                    getTranslateFromScale(-2, card2Scale),
                    getTranslateFromScale(-1, card1Scale),
                    0,
                    sizeRef * 0.5
                ],
                extrapolate: 'clamp'
            })
        }]
    } : {
        zIndex: carouselProps.data.length - index,
        opacity: animatedValue.interpolate({
            inputRange: [0, 1, 2, 3],
            outputRange: [1, 0.75, 0.5, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2],
                outputRange: [card1Scale, 1, card1Scale, card2Scale],
                extrapolate: 'clamp'
            })
        }, {
            [translateProp]: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2, 3],
                outputRange: [
                    -sizeRef * 0.5,
                    0,
                    getTranslateFromScale(1, card1Scale),
                    getTranslateFromScale(2, card2Scale),
                    getTranslateFromScale(3, card2Scale)
                ],
                extrapolate: 'clamp'
            })
        }]
    };
}

// Tinder animation
// Imitate the popular Tinder layout
// WARNING: The effect had to be visually inverted on Android because this OS doesn't honor the `zIndex`property
// This means that the item with the higher zIndex (and therefore the tap receiver) remains the one AFTER the currently active item
// The `elevation` property compensates for that only visually, which is not good enough
export function tinderScrollInterpolator (index, carouselProps) {
    const range = IS_ANDROID ?
        [1, 0, -1, -2, -3] :
        [3, 2, 1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = range;

    return { inputRange, outputRange };
}
export function tinderAnimatedStyles (index, animatedValue, carouselProps, cardOffset) {
    const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
    const mainTranslateProp = carouselProps.vertical ? 'translateY' : 'translateX';
    const secondaryTranslateProp = carouselProps.vertical ? 'translateX' : 'translateY';

    const card1Scale = 0.96;
    const card2Scale = 0.92;
    const card3Scale = 0.88;

    const peekingCardsOpacity = IS_ANDROID ? 0.92 : 1;

    cardOffset = !cardOffset && cardOffset !== 0 ? 9 : cardOffset;

    const getMainTranslateFromScale = (cardIndex, scale) => {
        const centerFactor = 1 / scale * cardIndex;
        return -Math.round(sizeRef * centerFactor);
    };

    const getSecondaryTranslateFromScale = (cardIndex, scale) => {
        return Math.round(cardOffset * Math.abs(cardIndex) / scale);
    };

    return IS_ANDROID ? {
        // elevation: carouselProps.data.length - index, // fix zIndex bug visually, but not from a logic point of view
        opacity: animatedValue.interpolate({
            inputRange: [-3, -2, -1, 0, 1],
            outputRange: [0, peekingCardsOpacity, peekingCardsOpacity, 1, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0],
                outputRange: [card3Scale, card2Scale, card1Scale, 1],
                extrapolate: 'clamp'
            })
        }, {
            rotate: animatedValue.interpolate({
                inputRange: [0, 1],
                outputRange: ['0deg', '22deg'],
                extrapolate: 'clamp'
            })
        }, {
            [mainTranslateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0, 1],
                outputRange: [
                    getMainTranslateFromScale(-3, card3Scale),
                    getMainTranslateFromScale(-2, card2Scale),
                    getMainTranslateFromScale(-1, card1Scale),
                    0,
                    sizeRef * 1.1
                ],
                extrapolate: 'clamp'
            })
        }, {
            [secondaryTranslateProp]: animatedValue.interpolate({
                inputRange: [-3, -2, -1, 0],
                outputRange: [
                    getSecondaryTranslateFromScale(-3, card3Scale),
                    getSecondaryTranslateFromScale(-2, card2Scale),
                    getSecondaryTranslateFromScale(-1, card1Scale),
                    0
                ],
                extrapolate: 'clamp'
            })
        }]
    } : {
        zIndex: carouselProps.data.length - index,
        opacity: animatedValue.interpolate({
            inputRange: [-1, 0, 1, 2, 3],
            outputRange: [0, 1, peekingCardsOpacity, peekingCardsOpacity, 0],
            extrapolate: 'clamp'
        }),
        transform: [{
            scale: animatedValue.interpolate({
                inputRange: [0, 1, 2, 3],
                outputRange: [1, card1Scale, card2Scale, card3Scale],
                extrapolate: 'clamp'
            })
        }, {
            rotate: animatedValue.interpolate({
                inputRange: [-1, 0],
                outputRange: ['-22deg', '0deg'],
                extrapolate: 'clamp'
            })
        }, {
            [mainTranslateProp]: animatedValue.interpolate({
                inputRange: [-1, 0, 1, 2, 3],
                outputRange: [
                    -sizeRef * 1.1,
                    0,
                    getMainTranslateFromScale(1, card1Scale),
                    getMainTranslateFromScale(2, card2Scale),
                    getMainTranslateFromScale(3, card3Scale)
                ],
                extrapolate: 'clamp'
            })
        }, {
            [secondaryTranslateProp]: animatedValue.interpolate({
                inputRange: [0, 1, 2, 3],
                outputRange: [
                    0,
                    getSecondaryTranslateFromScale(1, card1Scale),
                    getSecondaryTranslateFromScale(2, card2Scale),
                    getSecondaryTranslateFromScale(3, card3Scale)
                ],
                extrapolate: 'clamp'
            })
        }]
    };
}
<|endoftext|>


<commit_before>var http = require('http');
var Dockerode = require('dockerode');
var emptyPort = require('empty-port');
var thunkify = require('thunkify');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var config = require('../config');

module.exports = {
  readyContainer: readyContainer,
  createContainer: createContainer
}

var docker = new Dockerode(config.dockerOptions);
var emptyPort = thunkify(emptyPort);
docker.createContainer = thunkify(docker.createContainer);
mkdirp = thunkify(mkdirp);
rimraf = thunkify(rimraf);

function *startContainer(container) {
  var port = yield emptyPort({});
  var folder = __dirname + '/binds/' + container.id;
  yield mkdirp(folder);
  yield rimraf(folder + '/*');
  container.start = thunkify(container.start);
  yield container.start({
    Binds: [folder + ':/var/run']
  });
  yield waitForPort(folder);
  return port;
}

function *unpauseContainer(container) {
  container.unpause = thunkify(container.unpause);
  yield container.unpause();
  yield waitForPort(__dirname + '/binds/' + container.id);
}

function *waitForPort(folder) {
  var count = 1000;
  while (count-- > 0) {
    try {
      var result = yield get({ socketPath: folder + '/proxy' });
      break;
    } catch (error) {
      ignore(error);
    }
  }
  if (count < 1) {
    throw new Error('Could not connect to container');
  }
}

function get(options) {
  return function getThunk(cb) {
    setTimeout(function getAttempt () {
      var req = http.get(options);
      req.on('error', cb);
      req.on('response', function handleGetResponse(res) {
        res.on('error', cb);
        res.on('data', ignore);
        res.on('end', cb);
      });
    }, 50);
  };
}

function *readyContainer(name) {
  var container = docker.getContainer(name);
  container.inspect = thunkify(container.inspect);
  var info = yield container.inspect();
  if (!info.State.Running) {
    yield startContainer(container);
  }
  if (info.State.Paused) {
    yield unpauseContainer(container);
  }
}

function *createContainer(image) {
  var container = yield docker.createContainer({
    Image: config.imagePrefix + image,
    Hostname: image,
    Tty: true,
    Volumes: {
      '/var/run': {}
    }
  });
  container.inspect = thunkify(container.inspect);
  var info = yield container.inspect();
  return info.Name;
}

function ignore() {}
<commit_msg>paths<commit_after>var http = require('http');
var path = require('path');
var Dockerode = require('dockerode');
var emptyPort = require('empty-port');
var thunkify = require('thunkify');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var config = require('../config');

module.exports = {
  readyContainer: readyContainer,
  createContainer: createContainer
}

var docker = new Dockerode(config.dockerOptions);
var emptyPort = thunkify(emptyPort);
docker.createContainer = thunkify(docker.createContainer);
mkdirp = thunkify(mkdirp);
rimraf = thunkify(rimraf);

function *startContainer(container) {
  var port = yield emptyPort({});
  var folder = path.join(__dirname, 'binds', container.id);
  yield mkdirp(folder);
  yield rimraf(folder + '/*');
  container.start = thunkify(container.start);
  yield container.start({
    Binds: [folder + ':/var/run']
  });
  yield waitForPort(folder);
  return port;
}

function *unpauseContainer(container) {
  container.unpause = thunkify(container.unpause);
  yield container.unpause();
  yield waitForPort(path.join(__dirname, 'binds', container.id));
}

function *waitForPort(folder) {
  var count = 1000;
  while (count-- > 0) {
    try {
      var result = yield get({ socketPath: path.join(folder, 'proxy') });
      break;
    } catch (error) {
      ignore(error);
    }
  }
  if (count < 1) {
    throw new Error('Could not connect to container');
  }
}

function get(options) {
  return function getThunk(cb) {
    setTimeout(function getAttempt () {
      var req = http.get(options);
      req.on('error', cb);
      req.on('response', function handleGetResponse(res) {
        res.on('error', cb);
        res.on('data', ignore);
        res.on('end', cb);
      });
    }, 50);
  };
}

function *readyContainer(name) {
  var container = docker.getContainer(name);
  container.inspect = thunkify(container.inspect);
  var info = yield container.inspect();
  if (!info.State.Running) {
    yield startContainer(container);
  }
  if (info.State.Paused) {
    yield unpauseContainer(container);
  }
}

function *createContainer(image) {
  var container = yield docker.createContainer({
    Image: config.imagePrefix + image,
    Hostname: image,
    Tty: true,
    Volumes: {
      '/var/run': {}
    }
  });
  container.inspect = thunkify(container.inspect);
  var info = yield container.inspect();
  return info.Name;
}

function ignore() {}
<|endoftext|>


<commit_before>import { Platform, Dimensions } from "react-native";
import Constants from "expo-constants";

import { ScreenHit, PageHit, Event, Serializable } from "./hits";

const { width, height } = Dimensions.get("window");

let defaultOptions = { debug: false };

let webViewUserAgent = null;
const getWebViewUserAgent = async (options) => {
  return new Promise((resolve) => {
    if (options.userAgent) {
      webViewUserAgent = options.userAgent;
      return resolve(options.userAgent);
    }
    if (webViewUserAgent) return resolve(webViewUserAgent);
    Constants.getWebViewUserAgentAsync()
      .then((userAgent) => {
        webViewUserAgent = userAgent;
        resolve(userAgent);
      })
      .catch(() => resolve("unknown user agent"));
  });
};

export default class Analytics {
  customDimensions = [];
  customMetrics = [];

  constructor(propertyId, additionalParameters = {}, options = defaultOptions) {
    this.propertyId = propertyId;
    this.options = options;
    this.clientId = Constants.deviceId;
    this.parameters = {
      an: Constants.manifest.name,
      aid: Constants.manifest.slug,
      av: Constants.manifest.version,
      sr: `${width}x${height}`,
      ...additionalParameters,
    };

    this.promiseGetWebViewUserAgentAsync = getWebViewUserAgent(options).then(
      (userAgent) => {
        this.userAgent = userAgent;
        if (this.options.debug) {
          console.log(`[expo-analytics] UserAgent=${userAgent}`);
          console.log(
            `[expo-analytics] Additional parameters=`,
            this.parameters
          );
        }
      }
    );
  }

  hit(hit) {
    // send only after the user agent is saved
    return this.promiseGetWebViewUserAgentAsync.then(() => this.send(hit));
  }

  event(event) {
    // send only after the user agent is saved
    return this.promiseGetWebViewUserAgentAsync.then(() => this.send(event));
  }

  addParameter(name, value) {
    this.parameters[name] = value;
  }

  addCustomDimension(index, value) {
    this.customDimensions[index] = value;
  }

  removeCustomDimension(index) {
    delete this.customDimensions[index];
  }

  addCustomMetric(index, value) {
    this.customMetrics[index] = value;
  }

  removeCustomMetric(index) {
    delete this.customMetrics[index];
  }

  send(hit) {
    /* format: https://www.google-analytics.com/collect? +
     * &tid= GA property ID (required)
     * &v= GA protocol version (always 1) (required)
     * &t= hit type (pageview / screenview)
     * &dp= page name (if hit type is pageview)
     * &cd= screen name (if hit type is screenview)
     * &cid= anonymous client ID (optional if uid is given)
     * &uid= user id (optional if cid is given)
     * &ua= user agent override
     * &an= app name (required for any of the other app parameters to work)
     * &aid= app id
     * &av= app version
     * &sr= screen resolution
     * &cd{n}= custom dimensions
     * &cm{n}= custom metrics
     * &z= cache buster (prevent browsers from caching GET requests -- should always be last)
     *
     * Ecommerce track support (transaction)
     * &ti= transaction The transaction ID. (e.g. 1234)
     * &ta= The store or affiliation from which this transaction occurred (e.g. Acme Clothing).
     * &tr= Specifies the total revenue or grand total associated with the transaction (e.g. 11.99). This value may include shipping, tax costs, or other adjustments to total revenue that you want to include as part of your revenue calculations.
     * &tt= Specifies the total shipping cost of the transaction. (e.g. 5)
     *
     * Ecommerce track support (addItem)
     * &ti= transaction The transaction ID. (e.g. 1234)
     * &in= The item name. (e.g. Fluffy Pink Bunnies)
     * &ip= The individual, unit, price for each item. (e.g. 11.99)
     * &iq= The number of units purchased in the transaction. If a non-integer value is passed into this field (e.g. 1.5), it will be rounded to the closest integer value.
     * &ic= TSpecifies the SKU or item code. (e.g. SKU47)
     * &iv= The category to which the item belongs (e.g. Party Toys)
     */

    const customDimensions = this.customDimensions
      .map((value, index) => `cd${index}=${value}`)
      .join("&");
    const customMetrics = this.customMetrics
      .map((value, index) => `cm${index}=${value}`)
      .join("&");

    const params = new Serializable(this.parameters).toQueryString();

    const url = `https://www.google-analytics.com/collect?tid=${
      this.propertyId
    }&v=1&cid=${
      this.clientId
    }&${hit.toQueryString()}&${params}&${customDimensions}&${customMetrics}&z=${Math.round(
      Math.random() * 1e8
    )}`;

    let options;
    if (Platform.OS == "web") {
      options = {
        method: "get",
        headers: {
          "User-Agent": this.userAgent,
        },
        //Request opaque resources to avoid preflight CORS error in Safari
        mode: "no-cors",
      };
    } else {
      options = {
        method: "get",
        headers: {
          "User-Agent": this.userAgent,
        },
      };
    }

    if (this.options.debug) {
      console.log(`[expo-analytics] Sending GET request to ${url}`);
    }

    return fetch(url, options);
  }
}
<commit_msg>Fixed CORS preflight issue - kept formatting<commit_after>import { Platform, Dimensions } from 'react-native';
import Constants from 'expo-constants';

import { ScreenHit, PageHit, Event, Serializable } from './hits';

const { width, height } = Dimensions.get('window');

let defaultOptions = { debug: false };

let webViewUserAgent = null;
const getWebViewUserAgent = async (options) => {
    return new Promise((resolve) => {
        if (options.userAgent) {
            webViewUserAgent = options.userAgent;
            return resolve(options.userAgent);
        }
        if (webViewUserAgent) return resolve(webViewUserAgent);
        Constants.getWebViewUserAgentAsync()
          .then(userAgent => {
              webViewUserAgent = userAgent;
              resolve(userAgent);
          })
          .catch(() => resolve('unknown user agent'))
    });
}

export default class Analytics {
    customDimensions = []
    customMetrics = []

    constructor(propertyId, additionalParameters = {}, options = defaultOptions){
        this.propertyId = propertyId;
        this.options = options;
        this.clientId = Constants.deviceId;
        this.parameters = {
            an: Constants.manifest.name,
            aid: Constants.manifest.slug,
            av: Constants.manifest.version,
            sr: `${width}x${height}`,
            ...additionalParameters
        };

        this.promiseGetWebViewUserAgentAsync = getWebViewUserAgent(options)
            .then(userAgent => {
                this.userAgent = userAgent;
                if(this.options.debug){
                    console.log(`[expo-analytics] UserAgent=${userAgent}`);
                    console.log(`[expo-analytics] Additional parameters=`, this.parameters);
                }
            });
    }

    hit(hit){
        // send only after the user agent is saved
        return this.promiseGetWebViewUserAgentAsync
            .then(() => this.send(hit));
    }

    event(event){
        // send only after the user agent is saved
        return this.promiseGetWebViewUserAgentAsync
            .then(() => this.send(event));
    }

    addParameter(name, value){
        this.parameters[name] = value;
    }

    addCustomDimension(index, value){
        this.customDimensions[index] = value;
    }

    removeCustomDimension(index){
        delete this.customDimensions[index];
    }

    addCustomMetric(index, value) {
        this.customMetrics[index] = value;
      }

    removeCustomMetric(index) {
        delete this.customMetrics[index];
    }

    send(hit) {
        /* format: https://www.google-analytics.com/collect? +
        * &tid= GA property ID (required)
        * &v= GA protocol version (always 1) (required)
        * &t= hit type (pageview / screenview)
        * &dp= page name (if hit type is pageview)
        * &cd= screen name (if hit type is screenview)
        * &cid= anonymous client ID (optional if uid is given)
        * &uid= user id (optional if cid is given)
        * &ua= user agent override
        * &an= app name (required for any of the other app parameters to work)
        * &aid= app id
        * &av= app version
        * &sr= screen resolution
        * &cd{n}= custom dimensions
        * &cm{n}= custom metrics
        * &z= cache buster (prevent browsers from caching GET requests -- should always be last)
        *
        * Ecommerce track support (transaction)
        * &ti= transaction The transaction ID. (e.g. 1234)
        * &ta= The store or affiliation from which this transaction occurred (e.g. Acme Clothing).
        * &tr= Specifies the total revenue or grand total associated with the transaction (e.g. 11.99). This value may include shipping, tax costs, or other adjustments to total revenue that you want to include as part of your revenue calculations.
        * &tt= Specifies the total shipping cost of the transaction. (e.g. 5)
        *
        * Ecommerce track support (addItem)
        * &ti= transaction The transaction ID. (e.g. 1234)
        * &in= The item name. (e.g. Fluffy Pink Bunnies)
        * &ip= The individual, unit, price for each item. (e.g. 11.99)
        * &iq= The number of units purchased in the transaction. If a non-integer value is passed into this field (e.g. 1.5), it will be rounded to the closest integer value.
        * &ic= TSpecifies the SKU or item code. (e.g. SKU47)
        * &iv= The category to which the item belongs (e.g. Party Toys)
        */

        const customDimensions = this.customDimensions.map((value, index) => `cd${index}=${value}`).join('&');
        const customMetrics = this.customMetrics.map((value, index) => `cm${index}=${value}`).join('&');

        const params = new Serializable(this.parameters).toQueryString();

        const url = `https://www.google-analytics.com/collect?tid=${this.propertyId}&v=1&cid=${this.clientId}&${hit.toQueryString()}&${params}&${customDimensions}&${customMetrics}&z=${Math.round(Math.random() * 1e8)}`;

        let options;
        if (Platform.OS == "web") {
        options = {
            method: "get",
            headers: {
            "User-Agent": this.userAgent,
            },
            //Request opaque resources to avoid preflight CORS error in Safari
            mode: "no-cors",
        };
        } else {
        options = {
            method: "get",
            headers: {
            "User-Agent": this.userAgent,
            },
        };
        }

        if(this.options.debug){
            console.log(`[expo-analytics] Sending GET request to ${url}`);
        }

        return fetch(url, options);
    }

}
<|endoftext|>


<commit_before>let debug = false

/**
 * Console log depending on config debug mode
 * @param {...*} message
 */
const logDebug = function (message) {
  if (debug) {
    console.log('VueAnalytics :', ...arguments)
  }
}

/**
 * Plugin main class
 */
class AnalyticsPlugin {
  constructor (conf) {
    this.conf = conf
  }

  trackView (screenName) {
    logDebug('Dispatching TrackView', { screenName })

    ga('set', 'screenName', screenName)
    ga('send', 'screenview')
  }

  /**
   * Dispatch an analytics event
   *
   * @param category
   * @param action
   * @param label
   * @param value
   * @param fieldsObject
   */
  trackEvent (category, action = null, label = null, value = null, fieldsObject = {}) {
    // TODO : FieldObject is full syntax, refactor this
    logDebug('Dispatching event', { category, action, label, value, fieldsObject })

    ga('send', 'event', category, action, label, value, fieldsObject)
  }

  /**
   * Track an exception that occurred in the application.
   *
   * @param {string} description - Something describing the error (max. 150 Bytes)
   * @param {boolean} isFatal - Specifies whether the exception was fatal
   */
  trackException (description, isFatal = false) {
    ga('send', 'exception', { 'exDescription': description, 'exFatal': isFatal });
  }

  /**
   * Inject a new GlobalDimension that will be sent every time.
   *
   * Prefer inject through plugin configuration.
   *
   * @param {int} dimensionNumber
   * @param {string|int} value
   * @throws Error - If already defined
   */
  injectGlobalDimension (dimensionNumber, value) {
    logDebug('Trying dimension Injection...', { dimensionNumber, value })

    // Test if dimension already registered
    if (this.conf.globalDimensions.find(el => el.dimension === dimensionNumber)) {
      throw new Error('VueAnalytics : Dimension already registered')
    }

    // Otherwise add dimension
    const newDimension = { dimension: dimensionNumber, value }

    this.conf.globalDimensions.push(newDimension)
    ga('set', `dimension${newDimension.dimension}`, newDimension.value)
    logDebug('Dimension injected')
  }
}

/**
 * Installation procedure
 *
 * @param Vue
 * @param conf
 */
const install = function (Vue, conf) {

  // Default
  conf.debug = conf.debug || false
  debug = conf.debug // Module debug mode

  if (!conf.trackingId) {
    throw new Error('VueAnalytics : Please provide a "trackingId" from the config')
  }

  if (!conf.appName) {
    throw new Error('VueAnalytics : Please provide a "appName" from the config')
  }

  if (!conf.appVersion) {
    throw new Error('VueAnalytics : Please provide a "appVersion" from the config')
  }

  // Declare analytics snipper
  (function (i, s, o, g, r, a, m) {
    i[ 'GoogleAnalyticsObject' ] = r;
    i[ r ] = i[ r ] || function () {
        (i[ r ].q = i[ r ].q || []).push(arguments)
      }, i[ r ].l = 1 * new Date();
    a = s.createElement(o),
      m = s.getElementsByTagName(o)[ 0 ];
    a.async = 1;
    a.src = g;
    m.parentNode.insertBefore(a, m)
  })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

  // Register tracker, TODO : Set language and refactor in the create statement
  ga('create', conf.trackingId, 'auto')
  ga('set', 'appName', conf.appName)
  ga('set', 'appVersion', conf.appVersion)

  // Set beacon method if available
  // TODO : Simplify use, because the GA directive already fallback to default if not defined
  if (!conf.debug && navigator.sendBeacon) {
    ga('set', 'transport', 'beacon');
  }

  // Create global dimensions
  if (conf.globalDimensions) {
    conf.globalDimensions.forEach(dimension => {
      ga('set', `dimension${dimension.dimension}`, dimension.value)
    })
  }

  // Handle vue-router if defined
  if (conf.vueRouter) {
    // Flatten routes name
    if (conf.ignoredView) {
      conf.ignoredViews = conf.ignoredViews.map(view => view.toLowerCase())
    }

    conf.vueRouter.afterEach(({ name: routeName }) => {
      if (conf.ignoredViews && conf.ignoredViews.indexOf(routeName.toLowerCase()) !== -1) {
        return
      }

      // Dispatch vue event
      Vue.analytics.trackView(routeName)
    })
  }

  // Add to vue prototype and also from globals
  Vue.prototype.$analytics = Vue.prototype.$ua = Vue.analytics =  new AnalyticsPlugin(conf)
}

export default { install }<commit_msg>Repair error syntax<commit_after>let debug = false

/**
 * Console log depending on config debug mode
 * @param {...*} message
 */
const logDebug = function (message) {
  if (debug) {
    console.log('VueAnalytics :', ...arguments)
  }
}

/**
 * Plugin main class
 */
class AnalyticsPlugin {
  constructor (conf) {
    this.conf = conf
  }

  trackView (screenName) {
    logDebug('Dispatching TrackView', { screenName })

    ga('set', 'screenName', screenName)
    ga('send', 'screenview')
  }

  /**
   * Dispatch an analytics event
   *
   * @param category
   * @param action
   * @param label
   * @param value
   * @param fieldsObject
   */
  trackEvent (category, action = null, label = null, value = null, fieldsObject = {}) {
    // TODO : FieldObject is full syntax, refactor this
    logDebug('Dispatching event', { category, action, label, value, fieldsObject })

    ga('send', 'event', category, action, label, value, fieldsObject)
  }

  /**
   * Track an exception that occurred in the application.
   *
   * @param {string} description - Something describing the error (max. 150 Bytes)
   * @param {boolean} isFatal - Specifies whether the exception was fatal
   */
  trackException (description, isFatal = false) {
    ga('send', 'exception', { 'exDescription': description, 'exFatal': isFatal });
  }

  /**
   * Inject a new GlobalDimension that will be sent every time.
   *
   * Prefer inject through plugin configuration.
   *
   * @param {int} dimensionNumber
   * @param {string|int} value
   * @throws Error - If already defined
   */
  injectGlobalDimension (dimensionNumber, value) {
    logDebug('Trying dimension Injection...', { dimensionNumber, value })

    // Test if dimension already registered
    if (this.conf.globalDimensions.find(el => el.dimension === dimensionNumber)) {
      throw new Error('VueAnalytics : Dimension already registered')
    }

    // Otherwise add dimension
    const newDimension = { dimension: dimensionNumber, value }

    this.conf.globalDimensions.push(newDimension)
    ga('set', `dimension${newDimension.dimension}`, newDimension.value)
    logDebug('Dimension injected')
  }
}

/**
 * Installation procedure
 *
 * @param Vue
 * @param conf
 */
const install = function (Vue, conf) {

  // Default
  conf.debug = conf.debug || false
  debug = conf.debug // Module debug mode

  if (!conf.trackingId) {
    throw new Error('VueAnalytics : Please provide a "trackingId" from the config')
  }

  if (!conf.appName) {
    throw new Error('VueAnalytics : Please provide a "appName" from the config')
  }

  if (!conf.appVersion) {
    throw new Error('VueAnalytics : Please provide a "appVersion" from the config')
  }

  // Declare analytics snipper
  (function (i, s, o, g, r, a, m) {
    i[ 'GoogleAnalyticsObject' ] = r;
    i[ r ] = i[ r ] || function () {
        (i[ r ].q = i[ r ].q || []).push(arguments)
      }, i[ r ].l = 1 * new Date();
    a = s.createElement(o),
      m = s.getElementsByTagName(o)[ 0 ];
    a.async = 1;
    a.src = g;
    m.parentNode.insertBefore(a, m)
  })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

  // Register tracker, TODO : Set language and refactor in the create statement
  ga('create', conf.trackingId, 'auto')
  ga('set', 'appName', conf.appName)
  ga('set', 'appVersion', conf.appVersion)

  // Set beacon method if available
  // TODO : Simplify use, because the GA directive already fallback to default if not defined
  if (!conf.debug && navigator.sendBeacon) {
    ga('set', 'transport', 'beacon');
  }

  // Create global dimensions
  if (conf.globalDimensions) {
    conf.globalDimensions.forEach(dimension => {
      ga('set', `dimension${dimension.dimension}`, dimension.value)
    })
  }

  // Handle vue-router if defined
  if (conf.vueRouter) {
    // Flatten routes name
    if (conf.ignoredViews) {
      conf.ignoredViews = conf.ignoredViews.map(view => view.toLowerCase())
    }

    conf.vueRouter.afterEach(({ name: routeName }) => {
      if (conf.ignoredViews && conf.ignoredViews.indexOf(routeName.toLowerCase()) !== -1) {
        return
      }

      // Dispatch vue event
      Vue.analytics.trackView(routeName)
    })
  }

  // Add to vue prototype and also from globals
  Vue.prototype.$analytics = Vue.prototype.$ua = Vue.analytics =  new AnalyticsPlugin(conf)
}

export default { install }<|endoftext|>


<commit_before>import getFileExtension from './get-file-extension'
import Youtube from '../vendors/Youtube'
import Vimeo from '../vendors/Vimeo'
import Video from '../vendors/Video'
import Audio from '../vendors/Audio'

const VIDEO_EXTENSIONS = ['mp4', 'm4v', 'webm', 'ogv']
const AUDIO_EXTENSIONS = ['mp3', 'm4a', 'wav', 'ogg']

export default function getVendor(src) {
  const ext = getFileExtension(src)

  if (src.indexOf('youtube.com') > -1) {
    return Youtube
  } else if (src.indexOf('vimeo.com') > -1) {
    return Vimeo
  } else if (VIDEO_EXTENSIONS.indexOf(ext) > -1) {
    return Video
  } else if (AUDIO_EXTENSIONS.indexOf(ext) > -1) {
    return Audio
  } else {
    console.warn('Warning: Player was not rendered. Source could not be determined.')
    return null
  }
}
<commit_msg>check for youtube short urls<commit_after>import getFileExtension from './get-file-extension'
import Youtube from '../vendors/Youtube'
import Vimeo from '../vendors/Vimeo'
import Video from '../vendors/Video'
import Audio from '../vendors/Audio'

const VIDEO_EXTENSIONS = ['mp4', 'm4v', 'webm', 'ogv']
const AUDIO_EXTENSIONS = ['mp3', 'm4a', 'wav', 'ogg']

export default function getVendor(src) {
  const ext = getFileExtension(src)

  if (src.indexOf('youtube.com') > -1 || src.indexOf('youtu.be') > -1) {
    return Youtube
  } else if (src.indexOf('vimeo.com') > -1) {
    return Vimeo
  } else if (VIDEO_EXTENSIONS.indexOf(ext) > -1) {
    return Video
  } else if (AUDIO_EXTENSIONS.indexOf(ext) > -1) {
    return Audio
  } else {
    console.warn('Warning: Player was not rendered. Source could not be determined.')
    return null
  }
}
<|endoftext|>


<commit_before>'use babel'

import {Emitter, CompositeDisposable} from 'atom'
import Helpers from './helpers'

export default class EditorLinter {
  constructor(editor) {
    if (typeof editor !== 'object' || typeof editor.markBufferRange !== 'function') {
      throw new Error('Given editor is not really an editor')
    }

    this.editor = editor
    this.emitter = new Emitter()
    this.messages = new Set()
    this.markers = new Map()
    this.subscriptions = new CompositeDisposable
    this.gutter = null
    this.countLineMessages = 0

    this.subscriptions.add(atom.config.observe('linter.underlineIssues', underlineIssues =>
      this.underlineIssues = underlineIssues
    ))
    this.subscriptions.add(atom.config.observe('linter.showErrorInline', showBubble =>
      this.showBubble = showBubble
    ))
    this.subscriptions.add(this.editor.onDidDestroy(() =>
      this.dispose()
    ))
    this.subscriptions.add(this.editor.onDidSave(() =>
      this.emitter.emit('should-lint', false)
    ))
    this.subscriptions.add(this.editor.onDidChangeCursorPosition(({oldBufferPosition, newBufferPosition}) => {
      if (newBufferPosition.row !== oldBufferPosition.row) {
        this.calculateLineMessages(newBufferPosition.row)
      }
      this.emitter.emit('should-update-bubble')
    }))
    this.subscriptions.add(atom.config.observe('linter.gutterEnabled', gutterEnabled => {
      this.gutterEnabled = gutterEnabled
      this.handleGutter()
    }))
    // Using onDidChange instead of observe here 'cause the same function is invoked above
    this.subscriptions.add(atom.config.onDidChange('linter.gutterPosition', () =>
      this.handleGutter()
    ))
    this.subscriptions.add(this.onDidMessageAdd(message => {
      if (!this.underlineIssues && !this.gutterEnabled && !this.showBubble) {
        return // No-Op
      }
      const marker = this.editor.markBufferRange(message.range, {invalidate: 'inside'})
      this.markers.set(message, marker)
      if (this.underlineIssues) {
        this.editor.decorateMarker(marker, {
          type: 'highlight',
          class: `linter-highlight ${message.class}`
        })
      }
      if (this.gutterEnabled) {
        const item = document.createElement('span')
        item.className = `linter-gutter linter-highlight ${message.class}`
        this.gutter.decorateMarker(marker, {
          class: 'linter-row',
          item
        })
      }
    }))
    this.subscriptions.add(this.onDidMessageDelete(message => {
      if (this.markers.has(message)) {
        this.markers.get(message).destroy()
        this.markers.delete(message)
      }
    }))

    // TODO: Atom invokes onDid{Change, StopChanging} callbacks immediately. Workaround it
    atom.config.observe('linter.lintOnFlyInterval', (interval) => {
      if (this.changeSubscription) {
        this.changeSubscription.dispose()
      }
      this.changeSubscription = this.editor.onDidChange(Helpers.debounce(() => {
        this.emitter.emit('should-lint', true)
      }, interval))
    })

    this.active = true
  }

  set active(value) {
    value = Boolean(value)
    if (value !== this._active) {
      this._active = value
      if (this.messages.size) {
        this.messages.forEach(message => message.currentFile = value)
      }
    }
  }
  get active() {
    return this._active
  }

  handleGutter() {
    if (this.gutter !== null) {
      this.removeGutter()
    }
    if (this.gutterEnabled) {
      this.addGutter()
    }
  }

  addGutter() {
    const position = atom.config.get('linter.gutterPosition')
    this.gutter = this.editor.addGutter({
      name: 'linter',
      priority: position === 'Left' ? -100 : 100
    })
  }

  removeGutter() {
    if (this.gutter !== null) {
      try {
        // Atom throws when we try to remove a gutter container from a closed text editor
        this.gutter.destroy()
      } catch (err) {}
      this.gutter = null
    }
  }

  getMessages() {
    return this.messages
  }

  addMessage(message) {
    if (!this.messages.has(message)) {
      if (this.active) {
        message.currentFile = true
      }
      this.messages.add(message)
      this.emitter.emit('did-message-add', message)
      this.emitter.emit('did-message-change', {message, type: 'add'})
    }
  }

  deleteMessage(message) {
    if (this.messages.has(message)) {
      this.messages.delete(message)
      this.emitter.emit('did-message-delete', message)
      this.emitter.emit('did-message-change', {message, type: 'delete'})
    }
  }

  calculateLineMessages(row) {
    if (atom.config.get('linter.showErrorTabLine')) {
      if (row === null) {
        row = this.editor.getCursorBufferPosition().row
      }
      this.countLineMessages = 0
      this.messages.forEach(message => {
        if (message.currentLine = message.range && message.range.intersectsRow(row)) {
          this.countLineMessages++
        }
      })
    } else {
      this.countLineMessages = 0
    }
    this.emitter.emit('did-calculate-line-messages', this.countLineMessages)
    return this.countLineMessages
  }

  lint(onChange = false) {
    this.emitter.emit('should-lint', onChange)
  }

  onDidMessageAdd(callback) {
    return this.emitter.on('did-message-add', callback)
  }

  onDidMessageDelete(callback) {
    return this.emitter.on('did-message-delete', callback)
  }

  onDidMessageChange(callback) {
    return this.emitter.on('did-message-change', callback)
  }

  onDidCalculateLineMessages(callback) {
    return this.emitter.on('did-calculate-line-messages', callback)
  }

  onShouldUpdateBubble(callback) {
    return this.emitter.on('should-update-bubble', callback)
  }

  onShouldLint(callback) {
    return this.emitter.on('should-lint', callback)
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback)
  }

  dispose() {
    this.emitter.emit('did-destroy')
    if (this.markers.size) {
      this.markers.forEach(marker => marker.destroy())
      this.markers.clear()
    }
    this.removeGutter()
    this.subscriptions.dispose()
    if (this.changeSubscription) {
      this.changeSubscription.dispose()
    }
    this.emitter.dispose()
    this.messages.clear()
  }
}
<commit_msg>:bug: Ignore messages with no range in editor-linter<commit_after>'use babel'

import {Emitter, CompositeDisposable} from 'atom'
import Helpers from './helpers'

export default class EditorLinter {
  constructor(editor) {
    if (typeof editor !== 'object' || typeof editor.markBufferRange !== 'function') {
      throw new Error('Given editor is not really an editor')
    }

    this.editor = editor
    this.emitter = new Emitter()
    this.messages = new Set()
    this.markers = new Map()
    this.subscriptions = new CompositeDisposable
    this.gutter = null
    this.countLineMessages = 0

    this.subscriptions.add(atom.config.observe('linter.underlineIssues', underlineIssues =>
      this.underlineIssues = underlineIssues
    ))
    this.subscriptions.add(atom.config.observe('linter.showErrorInline', showBubble =>
      this.showBubble = showBubble
    ))
    this.subscriptions.add(this.editor.onDidDestroy(() =>
      this.dispose()
    ))
    this.subscriptions.add(this.editor.onDidSave(() =>
      this.emitter.emit('should-lint', false)
    ))
    this.subscriptions.add(this.editor.onDidChangeCursorPosition(({oldBufferPosition, newBufferPosition}) => {
      if (newBufferPosition.row !== oldBufferPosition.row) {
        this.calculateLineMessages(newBufferPosition.row)
      }
      this.emitter.emit('should-update-bubble')
    }))
    this.subscriptions.add(atom.config.observe('linter.gutterEnabled', gutterEnabled => {
      this.gutterEnabled = gutterEnabled
      this.handleGutter()
    }))
    // Using onDidChange instead of observe here 'cause the same function is invoked above
    this.subscriptions.add(atom.config.onDidChange('linter.gutterPosition', () =>
      this.handleGutter()
    ))
    this.subscriptions.add(this.onDidMessageAdd(message => {
      if (!this.underlineIssues && !this.gutterEnabled && !this.showBubble || !message.range) {
        return // No-Op
      }
      const marker = this.editor.markBufferRange(message.range, {invalidate: 'inside'})
      this.markers.set(message, marker)
      if (this.underlineIssues) {
        this.editor.decorateMarker(marker, {
          type: 'highlight',
          class: `linter-highlight ${message.class}`
        })
      }
      if (this.gutterEnabled) {
        const item = document.createElement('span')
        item.className = `linter-gutter linter-highlight ${message.class}`
        this.gutter.decorateMarker(marker, {
          class: 'linter-row',
          item
        })
      }
    }))
    this.subscriptions.add(this.onDidMessageDelete(message => {
      if (this.markers.has(message)) {
        this.markers.get(message).destroy()
        this.markers.delete(message)
      }
    }))

    // TODO: Atom invokes onDid{Change, StopChanging} callbacks immediately. Workaround it
    atom.config.observe('linter.lintOnFlyInterval', (interval) => {
      if (this.changeSubscription) {
        this.changeSubscription.dispose()
      }
      this.changeSubscription = this.editor.onDidChange(Helpers.debounce(() => {
        this.emitter.emit('should-lint', true)
      }, interval))
    })

    this.active = true
  }

  set active(value) {
    value = Boolean(value)
    if (value !== this._active) {
      this._active = value
      if (this.messages.size) {
        this.messages.forEach(message => message.currentFile = value)
      }
    }
  }
  get active() {
    return this._active
  }

  handleGutter() {
    if (this.gutter !== null) {
      this.removeGutter()
    }
    if (this.gutterEnabled) {
      this.addGutter()
    }
  }

  addGutter() {
    const position = atom.config.get('linter.gutterPosition')
    this.gutter = this.editor.addGutter({
      name: 'linter',
      priority: position === 'Left' ? -100 : 100
    })
  }

  removeGutter() {
    if (this.gutter !== null) {
      try {
        // Atom throws when we try to remove a gutter container from a closed text editor
        this.gutter.destroy()
      } catch (err) {}
      this.gutter = null
    }
  }

  getMessages() {
    return this.messages
  }

  addMessage(message) {
    if (!this.messages.has(message)) {
      if (this.active) {
        message.currentFile = true
      }
      this.messages.add(message)
      this.emitter.emit('did-message-add', message)
      this.emitter.emit('did-message-change', {message, type: 'add'})
    }
  }

  deleteMessage(message) {
    if (this.messages.has(message)) {
      this.messages.delete(message)
      this.emitter.emit('did-message-delete', message)
      this.emitter.emit('did-message-change', {message, type: 'delete'})
    }
  }

  calculateLineMessages(row) {
    if (atom.config.get('linter.showErrorTabLine')) {
      if (row === null) {
        row = this.editor.getCursorBufferPosition().row
      }
      this.countLineMessages = 0
      this.messages.forEach(message => {
        if (message.currentLine = message.range && message.range.intersectsRow(row)) {
          this.countLineMessages++
        }
      })
    } else {
      this.countLineMessages = 0
    }
    this.emitter.emit('did-calculate-line-messages', this.countLineMessages)
    return this.countLineMessages
  }

  lint(onChange = false) {
    this.emitter.emit('should-lint', onChange)
  }

  onDidMessageAdd(callback) {
    return this.emitter.on('did-message-add', callback)
  }

  onDidMessageDelete(callback) {
    return this.emitter.on('did-message-delete', callback)
  }

  onDidMessageChange(callback) {
    return this.emitter.on('did-message-change', callback)
  }

  onDidCalculateLineMessages(callback) {
    return this.emitter.on('did-calculate-line-messages', callback)
  }

  onShouldUpdateBubble(callback) {
    return this.emitter.on('should-update-bubble', callback)
  }

  onShouldLint(callback) {
    return this.emitter.on('should-lint', callback)
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback)
  }

  dispose() {
    this.emitter.emit('did-destroy')
    if (this.markers.size) {
      this.markers.forEach(marker => marker.destroy())
      this.markers.clear()
    }
    this.removeGutter()
    this.subscriptions.dispose()
    if (this.changeSubscription) {
      this.changeSubscription.dispose()
    }
    this.emitter.dispose()
    this.messages.clear()
  }
}
<|endoftext|>


<commit_before>'use babel'

import {TextEditor, Emitter, CompositeDisposable} from 'atom'
export default class EditorLinter {
  constructor(editor) {
    if (!(editor instanceof TextEditor)) {
      throw new Error('Given editor is not really an editor')
    }

    this.editor = editor
    this.emitter = new Emitter()
    this.messages = new Set()
    this.markers = new WeakMap()
    this.gutter = null
    this.gutterView = null
    this.subscriptions = new CompositeDisposable

    this.subscriptions.add(atom.config.observe('linter.underlineIssues', underlineIssues =>
      this.underlineIssues = underlineIssues
    ))
    this.subscriptions.add(this.editor.onDidDestroy(() =>
      this.destroy()
    ))
    this.subscriptions.add(this.editor.onDidSave(() =>
      this.emitter.emit('should-lint', false)
    ))
    this.subscriptions.add(this.editor.onDidChangeCursorPosition(({oldBufferPosition, newBufferPosition}) => {
      if (newBufferPosition.row !== oldBufferPosition.row) {
        this.emitter.emit('should-update-line-messages')
      }
      this.emitter.emit('should-update-bubble')
    }))
    this.subscriptions.add(atom.config.observe('linter.gutterEnabled', gutterEnabled => {
      this.gutterEnabled = gutterEnabled
      this.handleGutter()
    }))
    // Using onDidChange here 'cause the same function is invoked above
    this.subscriptions.add(atom.config.onDidChange('linter.gutterPosition', () =>
      this.handleGutter()
    ))
    this.subscriptions.add(this.onDidMessageAdd(message => {
      if (!this.underlineIssues && !this.gutterEnabled) {
        return // No-Op
      }
      const marker = this.editor.markBufferRange(message.range, {invalidate: 'inside'})
      this.markers.set(message, marker)
      if (this.underlineIssues) {
        this.editor.decorateMarker(marker, {
          type: 'highlight',
          class: `linter-highlight ${message.class}`
        })
      }
      if (this.gutterEnabled) {
        const item = document.createElement('span')
        item.className = `linter-gutter linter-highlight ${message.class}`
        //item.innerHTML = ' '
        this.gutter.decorateMarker(marker, {
          class: 'linter-row',
          item
        })
      }
    }))
    this.subscriptions.add(this.onDidMessageRemove(message => {
      if (this.markers.has(message)) {
        this.markers.get(message).destroy()
        this.markers.delete(message)
      }
    }))

    // Atom invokes the onDidStopChanging callback immediately on creation. So we wait a moment
    setImmediate(() => {
      this.subscriptions.add(this.editor.onDidStopChanging(() =>
        this.emitter.emit('should-lint', true)
      ))
    })
  }

  handleGutter() {
    if (this.gutter !== null) {
      this.removeGutter()
    }
    if (atom.config.get('linter.gutterEnabled')) {
      this.addGutter()
    }
  }

  addGutter() {
    const position = atom.config.get('linter.gutterPosition')
    this.gutter = this.editor.addGutter({
      name: 'linter',
      priority: position === 'Left' ? -100 : 100
    })
    this.gutterView = atom.views.getView(this.gutter)
  }

  removeGutter() {
    if (this.gutter !== null) {
      try {
        this.gutter.destroy()
        // Atom throws when we try to remove a container from a closed text editor
      } catch (err) {}
      this.gutter = null
      this.gutterView = null
    }
  }

  getMessages() {
    return this.messages
  }

  addMessage(message) {
    if (!this.messages.has(message)) {
      this.messages.add(message)
      this.emitter.emit('did-message-add', message)
      this.emitter.emit('did-message-change', {message, type: 'add'})
    }
  }

  removeMessage(message) {
    if (this.messages.has(message)) {
      this.messages.delete(message)
      this.emitter.emit('did-message-remove', message)
      this.emitter.emit('did-message-change', {message, type: 'remove'})
    }
  }

  lint(onChange = false) {
    this.emitter.emit('should-lint', onChange)
  }

  onDidMessageAdd(callback) {
    return this.emitter.on('did-message-add', callback)
  }

  onDidMessageRemove(callback) {
    return this.emitter.on('did-message-remove', callback)
  }

  onDidMessageChange(callback) {
    return this.emitter.on('did-message-change', callback)
  }

  onShouldUpdateBubble(callback) {
    return this.emitter.on('should-update-bubble', callback)
  }

  onShouldUpdateLineMessages(callback) {
    return this.emitter.on('should-update-line-messages', callback)
  }

  onShouldLint(callback) {
    return this.emitter.on('should-lint', callback)
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback)
  }

  destroy() {
    this.emitter.emit('did-destroy')
    this.dispose()
  }

  dispose() {
    if (this.markers.size) {
      this.markers.forEach(marker => marker.destroy())
      this.markers.clear()
    }
    this.removeGutter()
    this.subscriptions.dispose()
    this.messages.clear()
    this.emitter.dispose()
  }
}
<commit_msg>:fire: Remove EditorLinter::gutterView we no longer need that to monkey patch DOM<commit_after>'use babel'

import {TextEditor, Emitter, CompositeDisposable} from 'atom'
export default class EditorLinter {
  constructor(editor) {
    if (!(editor instanceof TextEditor)) {
      throw new Error('Given editor is not really an editor')
    }

    this.editor = editor
    this.emitter = new Emitter()
    this.messages = new Set()
    this.markers = new WeakMap()
    this.gutter = null
    this.subscriptions = new CompositeDisposable

    this.subscriptions.add(atom.config.observe('linter.underlineIssues', underlineIssues =>
      this.underlineIssues = underlineIssues
    ))
    this.subscriptions.add(this.editor.onDidDestroy(() =>
      this.destroy()
    ))
    this.subscriptions.add(this.editor.onDidSave(() =>
      this.emitter.emit('should-lint', false)
    ))
    this.subscriptions.add(this.editor.onDidChangeCursorPosition(({oldBufferPosition, newBufferPosition}) => {
      if (newBufferPosition.row !== oldBufferPosition.row) {
        this.emitter.emit('should-update-line-messages')
      }
      this.emitter.emit('should-update-bubble')
    }))
    this.subscriptions.add(atom.config.observe('linter.gutterEnabled', gutterEnabled => {
      this.gutterEnabled = gutterEnabled
      this.handleGutter()
    }))
    // Using onDidChange here 'cause the same function is invoked above
    this.subscriptions.add(atom.config.onDidChange('linter.gutterPosition', () =>
      this.handleGutter()
    ))
    this.subscriptions.add(this.onDidMessageAdd(message => {
      if (!this.underlineIssues && !this.gutterEnabled) {
        return // No-Op
      }
      const marker = this.editor.markBufferRange(message.range, {invalidate: 'inside'})
      this.markers.set(message, marker)
      if (this.underlineIssues) {
        this.editor.decorateMarker(marker, {
          type: 'highlight',
          class: `linter-highlight ${message.class}`
        })
      }
      if (this.gutterEnabled) {
        const item = document.createElement('span')
        item.className = `linter-gutter linter-highlight ${message.class}`
        //item.innerHTML = ' '
        this.gutter.decorateMarker(marker, {
          class: 'linter-row',
          item
        })
      }
    }))
    this.subscriptions.add(this.onDidMessageRemove(message => {
      if (this.markers.has(message)) {
        this.markers.get(message).destroy()
        this.markers.delete(message)
      }
    }))

    // Atom invokes the onDidStopChanging callback immediately on creation. So we wait a moment
    setImmediate(() => {
      this.subscriptions.add(this.editor.onDidStopChanging(() =>
        this.emitter.emit('should-lint', true)
      ))
    })
  }

  handleGutter() {
    if (this.gutter !== null) {
      this.removeGutter()
    }
    if (atom.config.get('linter.gutterEnabled')) {
      this.addGutter()
    }
  }

  addGutter() {
    const position = atom.config.get('linter.gutterPosition')
    this.gutter = this.editor.addGutter({
      name: 'linter',
      priority: position === 'Left' ? -100 : 100
    })
  }

  removeGutter() {
    if (this.gutter !== null) {
      try {
        this.gutter.destroy()
        // Atom throws when we try to remove a container from a closed text editor
      } catch (err) {}
      this.gutter = null
    }
  }

  getMessages() {
    return this.messages
  }

  addMessage(message) {
    if (!this.messages.has(message)) {
      this.messages.add(message)
      this.emitter.emit('did-message-add', message)
      this.emitter.emit('did-message-change', {message, type: 'add'})
    }
  }

  removeMessage(message) {
    if (this.messages.has(message)) {
      this.messages.delete(message)
      this.emitter.emit('did-message-remove', message)
      this.emitter.emit('did-message-change', {message, type: 'remove'})
    }
  }

  lint(onChange = false) {
    this.emitter.emit('should-lint', onChange)
  }

  onDidMessageAdd(callback) {
    return this.emitter.on('did-message-add', callback)
  }

  onDidMessageRemove(callback) {
    return this.emitter.on('did-message-remove', callback)
  }

  onDidMessageChange(callback) {
    return this.emitter.on('did-message-change', callback)
  }

  onShouldUpdateBubble(callback) {
    return this.emitter.on('should-update-bubble', callback)
  }

  onShouldUpdateLineMessages(callback) {
    return this.emitter.on('should-update-line-messages', callback)
  }

  onShouldLint(callback) {
    return this.emitter.on('should-lint', callback)
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback)
  }

  destroy() {
    this.emitter.emit('did-destroy')
    this.dispose()
  }

  dispose() {
    if (this.markers.size) {
      this.markers.forEach(marker => marker.destroy())
      this.markers.clear()
    }
    this.removeGutter()
    this.subscriptions.dispose()
    this.messages.clear()
    this.emitter.dispose()
  }
}
<|endoftext|>


<commit_before>import alpha from './alpha'
import alphaNum from './alphaNum'
import numeric from './numeric'
import between from './between'
import email from './email'
import ipAddress from './ipAddress'
import macAddress from './macAddress'
import maxLength from './maxLength'
import minLength from './minLength'
import required from './required'
import requiredIf from './requiredIf'
import requiredUnless from './requiredUnless'
import sameAs from './sameAs'
import url from './url'
import or from './or'
import and from './and'
import minValue from './minValue'
import maxValue from './maxValue'

export {
  alpha,
  alphaNum,
  numeric,
  between,
  email,
  ipAddress,
  macAddress,
  maxLength,
  minLength,
  required,
  requiredIf,
  requiredUnless,
  sameAs,
  url,
  or,
  and,
  minValue,
  maxValue
}
<commit_msg>Add integer and decimal validators to index.js<commit_after>import alpha from './alpha'
import alphaNum from './alphaNum'
import numeric from './numeric'
import between from './between'
import email from './email'
import ipAddress from './ipAddress'
import macAddress from './macAddress'
import maxLength from './maxLength'
import minLength from './minLength'
import required from './required'
import requiredIf from './requiredIf'
import requiredUnless from './requiredUnless'
import sameAs from './sameAs'
import url from './url'
import or from './or'
import and from './and'
import minValue from './minValue'
import maxValue from './maxValue'
import integer from './integer'
import decimal from './decimal'

export {
  alpha,
  alphaNum,
  numeric,
  between,
  email,
  ipAddress,
  macAddress,
  maxLength,
  minLength,
  required,
  requiredIf,
  requiredUnless,
  sameAs,
  url,
  or,
  and,
  minValue,
  maxValue,
  integer,
  decimal
}
<|endoftext|>


<commit_before>var nodemailer = require('nodemailer'),
    dataurl = require('dataurl');

exports.start = function (config_manager) {
    var transport;

    function updateConfig(appcfg) {
        var cfg = {
            host: appcfg.email_host,
            port: appcfg.email_port,
            auth: {
                user: appcfg.email_user,
                pass: appcfg.email_pass
            },
            secureConnection: appcfg.email_secure,
            service: appcfg.email_service
        };
        if (transport) {
            // retire old connection pool
            var _transport = transport;
            _transport.close();
        }
        // create new connection pool with updated config
        transport = nodemailer.createTransport("SMTP", cfg);
    }

    // set up initial config
    updateConfig(config_manager.getAppConfig());

    return {
        updateConfig: updateConfig,
        sendEmail: function (opt, callback) {
            try {
                // clone opt object as sendMail will extend it with
                // non JSON-serializable 'transport' property
                var email = JSON.parse(JSON.stringify(opt));
            }
            catch (e) {
                return callback(e);
            }
            if (email.attachments) {
                email.attachments = email.attachments.map(function (att) {
                    // strip filePath properties from attachments
                    delete att.filePath;
                    // parse dataURI properties
                    if (att.dataURI) {
                        var parsed = dataurl.parse(att.dataURI);
                        att.contents = parsed.data;
                        att.contentType = parsed.mimetype;
                        delete att.dataURI;
                    }
                    return att;
                });
            }
            return transport.sendMail(email, callback);
        },
        stop: function (callback) {
            return transport.close(callback);
        }
    };
};
<commit_msg>add .message property to nodemailer errors<commit_after>var nodemailer = require('nodemailer'),
    dataurl = require('dataurl');

exports.start = function (config_manager) {
    var transport;

    function updateConfig(appcfg) {
        var cfg = {
            host: appcfg.email_host,
            port: appcfg.email_port,
            auth: {
                user: appcfg.email_user,
                pass: appcfg.email_pass
            },
            secureConnection: appcfg.email_secure,
            service: appcfg.email_service
        };
        if (transport) {
            // retire old connection pool
            var _transport = transport;
            _transport.close();
        }
        // create new connection pool with updated config
        transport = nodemailer.createTransport("SMTP", cfg);
    }

    // set up initial config
    updateConfig(config_manager.getAppConfig());

    return {
        updateConfig: updateConfig,
        sendEmail: function (opt, callback) {
            try {
                // clone opt object as sendMail will extend it with
                // non JSON-serializable 'transport' property
                var email = JSON.parse(JSON.stringify(opt));
            }
            catch (e) {
                return callback(e);
            }
            if (email.attachments) {
                email.attachments = email.attachments.map(function (att) {
                    // strip filePath properties from attachments
                    delete att.filePath;
                    // parse dataURI properties
                    if (att.dataURI) {
                        var parsed = dataurl.parse(att.dataURI);
                        att.contents = parsed.data;
                        att.contentType = parsed.mimetype;
                        delete att.dataURI;
                    }
                    return att;
                });
            }
            return transport.sendMail(email, function (err) {
                if (err) {
                    // nodemailer errors are missing .message property
                    err.message = 'Could not deliver email: ' + err.data;
                }
                callback(err);
            });
        },
        stop: function (callback) {
            return transport.close(callback);
        }
    };
};
<|endoftext|>


<commit_before>(function(red, $) {
var cjs = red.cjs, _ = red._;

$.widget("red.editor", {

	options: {
		debug_ready: false,
		debug_env: false,
		command_box: false,
		server_window: window.opener
	}

	, _create: function() {
		if(this.options.command_box) {
			this.command_box = $("<input />")	.prependTo(this.element.parent())
												.focus()
												.on("keydown", _.bind(function(event) {
													if(event.keyCode === 13) {
														var val = this.command_box.val();
														this.command_box.val("");
														this.on_input_command(val);
													}
												}, this));
		}

		this.env = red.create("environment");
		if(this.option("debug_env")) {
			window.output_env = this.env;
		}
		this.root = this.env.get_root();
		this.element.dom_output({
			root: this.root
		});

		this.client_socket = new red.ProgramStateClient({
			ready_func: this.option("debug_ready"),
			server_window: this.option("server_window")
		}).on("message", function(data) {
			if(data.type === "color") {
				var color = data.value;
				$("html").css({
					"border-bottom": "10px solid " + color,
					"min-height": "100%",
					"box-sizing": "border-box"
				});
			}
		}, this).on("loaded", function(root_client) {
			this.root.set("root_client", root_client, {literal: true});
			window.rc = root_client;
			this.load_viewer();
		}, this);
	}

	, load_viewer: function() {
		this.env.top()

// ===== BEGIN EDITOR =====

.set("ambiguous_view", "<stateful>")
.cd("ambiguous_view")
	.set("(protos)", "INIT", "type === 'stateful' ? [dict_view] : type === 'dict' ? [dict_view] : type === 'stateful_prop' ? [stateful_prop_view] : type === 'cell' ? [cell_view] : type === 'statechart' ? [statecuart_view] : [value_view]")
	.set("client")
	.set("client", "INIT", "false")
	.set("type", "INIT", "client && client.type ? client.type() : ''")
	.up()
.set("stateful_prop_view", "<stateful>")
.cd("stateful_prop_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("children", "<dict>")
	.cd("children")
		.set("values", "<stateful>")
		.cd("values")
			.set("(protos)", "INIT", "[cell_view]")
			.set("(manifestations)", "INIT", "parent.parent.client.get('get_values')")
			.set("client", "this.basis.value")
			.set("inherited", "this.basis.inherited")
			.up()
		.up()
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'stateful_prop'")
		.up()
	.up()
.set("value_view", "<stateful>")
.cd("value_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("text")
	.set("text", "INIT", "''")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "' '")
		.up()
	.up()
.set("cell_view", "<stateful>")
.cd("cell_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("text")
	.set("text", "INIT", "client.get('get_str')")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'cell' + (parent.inherited ? ' inherited' : '')")
		.up()
	.up()
.set("statechart_view", "<stateful>")
.cd("statechart_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'div'")
	.set("children", "<stateful_prop>")
	.set("children", "INIT", "get_statechart_view(client.get('get_own_statechart'))")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'statechart'")
		.up()
	.up()
.set("dict_view", "<stateful>")
.cd("dict_view")
	.set("(protos)", "INIT", "[dom]")
	.set("children", "<dict>")
	.cd("children")
		.set("statechart_disp", "<stateful>")
		.cd("statechart_disp")
			.set("(protos)", "client.type() === 'stateful' ? [statechart_view] : []")
			.up()
		.set("child_disp", "<stateful>")
		.cd("child_disp")
			.set("(protos)", "INIT", "[dom]")
			.set("(manifestations)", "client.get('children')")
			.set("attr", "<dict>")
			.cd("attr")
				.set("class", "'dict_child' + (parent.basis.inherited ? ' inherited' : '')")
				.up()
			.set("children", "<dict>")
			.cd("children")
				.set("prop_name", "<stateful>")
				.cd("prop_name")
					.set("(protos)", "[dom]")
					.set("tag")
					.set("tag", "INIT", "'span'")
					.set("text")
					.set("text", "INIT", "parent.parent.basis.value && (parent.parent.basis.value.type() === 'dict' ||  parent.parent.basis.value.type() === 'stateful') ? basis.name + ':' : basis.name")
					.set("attr", "<dict>")
					.cd("attr")
						.set("class", "'prop_name'")
						.up()
					.up()
				.set("prop_value", "<stateful>")
				.cd("prop_value")
					.set("(protos)", "[dom]")
					.set("tag")
					.set("tag", "INIT", "'span'")
					.set("text")
					.set("text", "INIT", "print_value(parent.parent.basis.value)")
					.set("attr", "<dict>")
					.cd("attr")
						.set("class", "'value'")
						.up()
					.up()
				.set("prop_src", "<stateful>")
				.cd("prop_src")
					.set("(protos)", "[ambiguous_view]")
					.set("client", "parent.parent.basis.value || false")
					.up()
				.up()
			.up()
		.up()
	.up()
.cd("children")
	.set("obj", "<stateful>")
	.cd("obj")
		.set("(protos)", "INIT", "[ambiguous_view]")
		.set("client")
		.set("client", "INIT", "root_client")
		.up()
	.up()
.set("get_statechart_view", function(cobj) {
	if(cobj) {
		var id = cobj.cobj_id;
		var statechart = red.find_uid(id);
		//var statechart = cobj.get_own_statechart();
		var content = document.createElement("div");
		var el = document.createElement("div");
		el.style.position = "relative";
		el.style.left = "300px";
		content.appendChild(el);
		var paper = Raphael(el, 600, 200);
		var scv = red.create("statechart_view", statechart, paper, {root: true});
		return content;
	}
})
.set("print_value",
"function(client) {\n" +
	"var type = client && client.type ? client.type() : '';\n"+
	"var rv;\n"+

	"if(type === 'cell' || type === 'stateful_prop') {\n"+
		"rv = client.get('val');\n"+
	"} else if(type === 'dict' || type === 'stateful') {\n"+
		"return '';\n"+
	"} else if(type === '') {\n"+
	/*
		"if(client === undefined) {\n"+
			"rv = '(undefined)';\n"+
		"} else if(client === null) {\n"+
			"rv = '(null)';\n"+
		"} else if(client === true) {\n"+
			"rv = '(true)';\n"+
		"} else if(client === false) {\n"+
			"rv = '(false)';\n"+
		"} else {\n"+
		*/
			"rv = client;\n"+
			/*
		"}\n"+
		*/
	"}\n"+

	"if(typeof rv === 'string' && rv[0] !== '(') {\n"+
		"return '\"' + rv + '\"';\n"+
	"} else {\n"+
		"return ''+rv;\n"+
	"}\n"+
"}");

// ===== END EDITOR =====
//this.env.print();
		if(this.option("debug_env")) {
			this.env.print_on_return = true;
		}
	}

	, _destroy: function() {
		this.remove_message_listener();
		this.client_socket.destroy();
		if(this.command_box) {
			this.command_box.remove();
		}
	}

	, on_input_command: function(value) {
		var tokens = aware_split(value).map(function(token) {
			return token.trim();
		});
		var command;
		if((["undo", "redo", "reset"]).indexOf(tokens[0]) >= 0) {
			command = tokens[0];
			this.client_socket.post_command(command);
		} else {
			var external_env = this.client_socket.get_external_env();
			command = external_env[tokens[0]].apply(external_env, _.rest(tokens));
			if(command instanceof red.Command) {
				this.client_socket.post_command(command);
			}
		}
	}
});

}(red, jQuery));
<commit_msg>sniff one<commit_after>(function(red, $) {
var cjs = red.cjs, _ = red._;

$.widget("red.editor", {

	options: {
		debug_ready: false,
		debug_env: false,
		command_box: false,
		server_window: window.opener
	}

	, _create: function() {
		if(this.options.command_box) {
			this.command_box = $("<input />")	.prependTo(this.element.parent())
												.focus()
												.on("keydown", _.bind(function(event) {
													if(event.keyCode === 13) {
														var val = this.command_box.val();
														this.command_box.val("");
														this.on_input_command(val);
													}
												}, this));
		}

		this.env = red.create("environment");
		if(this.option("debug_env")) {
			window.output_env = this.env;
		}
		this.root = this.env.get_root();
		this.element.dom_output({
			root: this.root
		});

		this.client_socket = new red.ProgramStateClient({
			ready_func: this.option("debug_ready"),
			server_window: this.option("server_window")
		}).on("message", function(data) {
			if(data.type === "color") {
				var color = data.value;
				$("html").css({
					"border-bottom": "10px solid " + color,
					"min-height": "100%",
					"box-sizing": "border-box"
				});
			}
		}, this).on("loaded", function(root_client) {
			this.root.set("root_client", root_client, {literal: true});
			window.rc = root_client;
			this.load_viewer();
		}, this);
	}

	, load_viewer: function() {
		this.env.top()

// ===== BEGIN EDITOR =====

.set("ambiguous_view", "<stateful>")
.cd("ambiguous_view")
	.set("(protos)", "INIT", "type === 'stateful' ? [dict_view] : type === 'dict' ? [dict_view] : type === 'stateful_prop' ? [stateful_prop_view] : type === 'cell' ? [cell_view] : type === 'statechart' ? [statecuart_view] : [value_view]")
	.set("client")
	.set("client", "INIT", "false")
	.set("type", "INIT", "client && client.type ? client.type() : ''")
	.up()
.set("stateful_prop_view", "<stateful>")
.cd("stateful_prop_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("children", "<dict>")
	.cd("children")
		.set("values", "<stateful>")
		.cd("values")
			.set("(protos)", "INIT", "[cell_view]")
			.set("(manifestations)", "INIT", "parent.parent.client.get('get_values')")
			.set("client", "this.basis.value")
			.set("inherited", "this.basis.inherited")
			.up()
		.up()
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'stateful_prop'")
		.up()
	.up()
.set("value_view", "<stateful>")
.cd("value_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("text")
	.set("text", "INIT", "''")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "' '")
		.up()
	.up()
.set("cell_view", "<stateful>")
.cd("cell_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'span'")
	.set("text")
	.set("text", "INIT", "client.get('get_str')")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'cell' + (parent.inherited ? ' inherited' : '')")
		.up()
	.up()
.set("statechart_view", "<stateful>")
.cd("statechart_view")
	.set("(protos)", "INIT", "[dom]")
	.set("tag")
	.set("tag", "INIT", "'div'")
	.set("children", "<stateful_prop>")
	.set("children", "INIT", "get_statechart_view(client.get('get_own_statechart'))")
	.set("attr", "<dict>")
	.cd("attr")
		.set("class", "'statechart'")
		.up()
	.up()
.set("dict_view", "<stateful>")
.cd("dict_view")
	.set("(protos)", "INIT", "[dom]")
	.set("children", "<dict>")
	.cd("children")
		.set("statechart_disp", "<stateful>")
		.cd("statechart_disp")
			.set("(protos)", "client.type() === 'stateful' ? [statechart_view] : []")
			.up()
		.set("child_disp", "<stateful>")
		.cd("child_disp")
			.set("(protos)", "INIT", "[dom]")
			.set("(manifestations)", "client.get('children')")
			.set("attr", "<dict>")
			.cd("attr")
				.set("class", "'dict_child' + (parent.basis.inherited ? ' inherited' : '')")
				.up()
			.set("children", "<dict>")
			.cd("children")
				.set("prop_name", "<stateful>")
				.cd("prop_name")
					.set("(protos)", "[dom]")
					.set("tag")
					.set("tag", "INIT", "'span'")
					.set("text")
					.set("text", "INIT", "parent.parent.basis.value && (parent.parent.basis.value.type() === 'dict' ||  parent.parent.basis.value.type() === 'stateful') ? basis.name + ':' : basis.name")
					.set("attr", "<dict>")
					.cd("attr")
						.set("class", "'prop_name'")
						.up()
					.up()
				.set("prop_value", "<stateful>")
				.cd("prop_value")
					.set("(protos)", "[dom]")
					.set("tag")
					.set("tag", "INIT", "'span'")
					.set("text")
					.set("text", "INIT", "print_value(parent.parent.basis.value)")
					.set("attr", "<dict>")
					.cd("attr")
						.set("class", "'value'")
						.up()
					.up()
				.set("prop_src", "<stateful>")
				.cd("prop_src")
					.set("(protos)", "[ambiguous_view]")
					.set("client", "parent.parent.basis.value || false")
					.up()
				.up()
			.up()
		.up()
	.up()
.cd("children")
	.set("obj", "<stateful>")
	.cd("obj")
		.set("(protos)", "INIT", "[ambiguous_view]")
		.set("client")
		.set("client", "INIT", "root_client")
		.up()
	.up()
.set("get_statechart_view", function(cobj) {
	if(cobj) {
		var id = cobj.cobj_id;
		var statechart = red.find_uid(id);
		//var statechart = cobj.get_own_statechart();
		var content = document.createElement("div");
		if(statechart) {
			var el = document.createElement("div");
			el.style.position = "relative";
			el.style.left = "300px";
			content.appendChild(el);
			var paper = Raphael(el, 600, 200);
			var scv = red.create("statechart_view", statechart, paper, {root: true});
		} else {
			content.textContent = "(waiting for statechart to load)";
		}
		return content;
	}
})
.set("print_value",
"function(client) {\n" +
	"var type = client && client.type ? client.type() : '';\n"+
	"var rv;\n"+

	"if(type === 'cell' || type === 'stateful_prop') {\n"+
		"rv = client.get('val');\n"+
	"} else if(type === 'dict' || type === 'stateful') {\n"+
		"return '';\n"+
	"} else if(type === '') {\n"+
	/*
		"if(client === undefined) {\n"+
			"rv = '(undefined)';\n"+
		"} else if(client === null) {\n"+
			"rv = '(null)';\n"+
		"} else if(client === true) {\n"+
			"rv = '(true)';\n"+
		"} else if(client === false) {\n"+
			"rv = '(false)';\n"+
		"} else {\n"+
		*/
			"rv = client;\n"+
			/*
		"}\n"+
		*/
	"}\n"+

	"if(typeof rv === 'string' && rv[0] !== '(') {\n"+
		"return '\"' + rv + '\"';\n"+
	"} else {\n"+
		"return ''+rv;\n"+
	"}\n"+
"}");

// ===== END EDITOR =====
//this.env.print();
		if(this.option("debug_env")) {
			this.env.print_on_return = true;
		}
	}

	, _destroy: function() {
		this.remove_message_listener();
		this.client_socket.destroy();
		if(this.command_box) {
			this.command_box.remove();
		}
	}

	, on_input_command: function(value) {
		var tokens = aware_split(value).map(function(token) {
			return token.trim();
		});
		var command;
		if((["undo", "redo", "reset"]).indexOf(tokens[0]) >= 0) {
			command = tokens[0];
			this.client_socket.post_command(command);
		} else {
			var external_env = this.client_socket.get_external_env();
			command = external_env[tokens[0]].apply(external_env, _.rest(tokens));
			if(command instanceof red.Command) {
				this.client_socket.post_command(command);
			}
		}
	}
});

}(red, jQuery));
<|endoftext|>