Plato on Github
Report Home
src\ngAnimate\animateCss.js
Maintainability
61.73
Lines of code
953
Difficulty
72.30
Estimated Errors
6.36
Function weight
By Complexity
By SLOC
'use strict'; /** * @ngdoc service * @name $animateCss * @kind object * * @description * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or * directives to create more complex animations that can be purely driven using CSS code. * * Note that only browsers that support CSS transitions and/or keyframe animations are capable of * rendering animations triggered via `$animateCss` (bad news for IE9 and lower). * * ## Usage * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however, * any automatic control over cancelling animations and/or preventing animations from being run on * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger * the CSS animation. * * The example below shows how we can create a folding animation on an element using `ng-if`: * * ```html * <!-- notice the `fold-animation` CSS class --> * <div ng-if="onOff" class="fold-animation"> * This element will go BOOM * </div> * <button ng-click="onOff=true">Fold In</button> * ``` * * Now we create the **JavaScript animation** that will trigger the CSS transition: * * ```js * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { * return { * enter: function(element, doneFn) { * var height = element[0].offsetHeight; * return $animateCss(element, { * from: { height:'0px' }, * to: { height:height + 'px' }, * duration: 1 // one second * }); * } * } * }]); * ``` * * ## More Advanced Uses * * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code. * * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation, * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order * to provide a working animation that will run in CSS. * * The example below showcases a more advanced version of the `.fold-animation` from the example above: * * ```js * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { * return { * enter: function(element, doneFn) { * var height = element[0].offsetHeight; * return $animateCss(element, { * addClass: 'red large-text pulse-twice', * easing: 'ease-out', * from: { height:'0px' }, * to: { height:height + 'px' }, * duration: 1 // one second * }); * } * } * }]); * ``` * * Since we're adding/removing CSS classes then the CSS transition will also pick those up: * * ```css * /* since a hardcoded duration value of 1 was provided in the JavaScript animation code, * the CSS classes below will be transitioned despite them being defined as regular CSS classes */ * .red { background:red; } * .large-text { font-size:20px; } * * /* we can also use a keyframe animation and $animateCss will make it work alongside the transition */ * .pulse-twice { * animation: 0.5s pulse linear 2; * -webkit-animation: 0.5s pulse linear 2; * } * * @keyframes pulse { * from { transform: scale(0.5); } * to { transform: scale(1.5); } * } * * @-webkit-keyframes pulse { * from { -webkit-transform: scale(0.5); } * to { -webkit-transform: scale(1.5); } * } * ``` * * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen. * * ## How the Options are handled * * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline * styles using the `from` and `to` properties. * * ```js * var animator = $animateCss(element, { * from: { background:'red' }, * to: { background:'blue' } * }); * animator.start(); * ``` * * ```css * .rotating-animation { * animation:0.5s rotate linear; * -webkit-animation:0.5s rotate linear; * } * * @keyframes rotate { * from { transform: rotate(0deg); } * to { transform: rotate(360deg); } * } * * @-webkit-keyframes rotate { * from { -webkit-transform: rotate(0deg); } * to { -webkit-transform: rotate(360deg); } * } * ``` * * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied * and spread across the transition and keyframe animation. * * ## What is returned * * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties: * * ```js * var animator = $animateCss(element, { ... }); * ``` * * Now what do the contents of our `animator` variable look like: * * ```js * { * // starts the animation * start: Function, * * // ends (aborts) the animation * end: Function * } * ``` * * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends. * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties * and that changing them will not reconfigure the parameters of the animation. * * ### runner.done() vs runner.then() * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**. * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()` * unless you really need a digest to kick off afterwards. * * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code). * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works. * * @param {DOMElement} element the element that will be animated * @param {object} options the animation-related options that will be applied during the animation * * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.) * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both). * * `transition` - The raw CSS transition style that will be used (e.g. `1s linear all`). * * `keyframe` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`). * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation. * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition. * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation. * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation. * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0` * is provided then the animation will be skipped entirely. * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same * CSS delay value. * * `stagger` - A numeric time value representing the delay between successively animated elements * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.}) * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`) * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.) * * @return {object} an object with start and end methods and details about the animation. * * * `start` - The method to start the animation. This will return a `Promise` when called. * * `end` - This method will cancel the animation and remove all applied CSS classes and styles. */ // Detect proper transitionend/animationend event names. var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT; // If unprefixed events are not supported but webkit-prefixed are, use the latter. // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them. // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend` // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`. // Register both events in case `window.onanimationend` is not supported because of that, // do the same for `transitionend` as Safari is likely to exhibit similar behavior. // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit // therefore there is no reason to test anymore for other vendor prefixes: // http://caniuse.com/#search=transition if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { CSS_PREFIX = '-webkit-'; TRANSITION_PROP = 'WebkitTransition'; TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; } else { TRANSITION_PROP = 'transition'; TRANSITIONEND_EVENT = 'transitionend'; } if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) { CSS_PREFIX = '-webkit-'; ANIMATION_PROP = 'WebkitAnimation'; ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; } else { ANIMATION_PROP = 'animation'; ANIMATIONEND_EVENT = 'animationend'; } var DURATION_KEY = 'Duration'; var PROPERTY_KEY = 'Property'; var DELAY_KEY = 'Delay'; var TIMING_KEY = 'TimingFunction'; var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; var ANIMATION_PLAYSTATE_KEY = 'PlayState'; var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; var CLOSING_TIME_BUFFER = 1.5; var ONE_SECOND = 1000; var BASE_TEN = 10; var SAFE_FAST_FORWARD_DURATION_VALUE = 9999; var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY; var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY; var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY; var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY; var DETECT_CSS_PROPERTIES = { transitionDuration: TRANSITION_DURATION_PROP, transitionDelay: TRANSITION_DELAY_PROP, transitionProperty: TRANSITION_PROP + PROPERTY_KEY, animationDuration: ANIMATION_DURATION_PROP, animationDelay: ANIMATION_DELAY_PROP, animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY }; var DETECT_STAGGER_CSS_PROPERTIES = { transitionDuration: TRANSITION_DURATION_PROP, transitionDelay: TRANSITION_DELAY_PROP, animationDuration: ANIMATION_DURATION_PROP, animationDelay: ANIMATION_DELAY_PROP }; function computeCssStyles($window, element, properties) { var styles = Object.create(null); var detectedStyles = $window.getComputedStyle(element) || {}; forEach(properties, function(formalStyleName, actualStyleName) { var val = detectedStyles[formalStyleName]; if (val) { var c = val.charAt(0); // only numerical-based values have a negative sign or digit as the first value if (c === '-' || c === '+' || c >= 0) { val = parseMaxTime(val); } // by setting this to null in the event that the delay is not set or is set directly as 0 // then we can still allow for zegative values to be used later on and not mistake this // value for being greater than any other negative value. if (val === 0) { val = null; } styles[actualStyleName] = val; } }); return styles; } function parseMaxTime(str) { var maxValue = 0; var values = str.split(/\s*,\s*/); forEach(values, function(value) { // it's always safe to consider only second values and omit `ms` values since // getComputedStyle will always handle the conversion for us if (value.charAt(value.length - 1) == 's') { value = value.substring(0, value.length - 1); } value = parseFloat(value) || 0; maxValue = maxValue ? Math.max(value, maxValue) : value; }); return maxValue; } function truthyTimingValue(val) { return val === 0 || val != null; } function getCssTransitionDurationStyle(duration, applyOnlyDuration) { var style = TRANSITION_PROP; var value = duration + 's'; if (applyOnlyDuration) { style += DURATION_KEY; } else { value += ' linear all'; } return [style, value]; } function getCssKeyframeDurationStyle(duration) { return [ANIMATION_DURATION_PROP, duration + 's']; } function getCssDelayStyle(delay, isKeyframeAnimation) { var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP; return [prop, delay + 's']; } function blockTransitions(node, duration) { // we use a negative delay value since it performs blocking // yet it doesn't kill any existing transitions running on the // same element which makes this safe for class-based animations var value = duration ? '-' + duration + 's' : ''; applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]); return [TRANSITION_DELAY_PROP, value]; } function blockKeyframeAnimations(node, applyBlock) { var value = applyBlock ? 'paused' : ''; var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY; applyInlineStyle(node, [key, value]); return [key, value]; } function applyInlineStyle(node, styleTuple) { var prop = styleTuple[0]; var value = styleTuple[1]; node.style[prop] = value; } function createLocalCacheLookup() { var cache = Object.create(null); return { flush: function() { cache = Object.create(null); }, count: function(key) { var entry = cache[key]; return entry ? entry.total : 0; }, get: function(key) { var entry = cache[key]; return entry && entry.value; }, put: function(key, value) { if (!cache[key]) { cache[key] = { total: 1, value: value }; } else { cache[key].total++; } } }; } var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { var gcsLookup = createLocalCacheLookup(); var gcsStaggerLookup = createLocalCacheLookup(); this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$document', '$sniffer', '$$rAFScheduler', function($window, $$jqLite, $$AnimateRunner, $timeout, $document, $sniffer, $$rAFScheduler) { var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); var parentCounter = 0; function gcsHashFn(node, extraClasses) { var KEY = "$$ngAnimateParentKey"; var parentNode = node.parentNode; var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter); return parentID + '-' + node.getAttribute('class') + '-' + extraClasses; } function computeCachedCssStyles(node, className, cacheKey, properties) { var timings = gcsLookup.get(cacheKey); if (!timings) { timings = computeCssStyles($window, node, properties); if (timings.animationIterationCount === 'infinite') { timings.animationIterationCount = 1; } } // we keep putting this in multiple times even though the value and the cacheKey are the same // because we're keeping an interal tally of how many duplicate animations are detected. gcsLookup.put(cacheKey, timings); return timings; } function computeCachedCssStaggerStyles(node, className, cacheKey, properties) { var stagger; // if we have one or more existing matches of matching elements // containing the same parent + CSS styles (which is how cacheKey works) // then staggering is possible if (gcsLookup.count(cacheKey) > 0) { stagger = gcsStaggerLookup.get(cacheKey); if (!stagger) { var staggerClassName = pendClasses(className, '-stagger'); $$jqLite.addClass(node, staggerClassName); stagger = computeCssStyles($window, node, properties); // force the conversion of a null value to zero incase not set stagger.animationDuration = Math.max(stagger.animationDuration, 0); stagger.transitionDuration = Math.max(stagger.transitionDuration, 0); $$jqLite.removeClass(node, staggerClassName); gcsStaggerLookup.put(cacheKey, stagger); } } return stagger || {}; } var bod = getDomNode($document).body; var rafWaitQueue = []; function waitUntilQuiet(callback) { rafWaitQueue.push(callback); $$rAFScheduler.waitUntilQuiet(function() { gcsLookup.flush(); gcsStaggerLookup.flush(); //the line below will force the browser to perform a repaint so //that all the animated elements within the animation frame will //be properly updated and drawn on screen. This is required to //ensure that the preparation animation is properly flushed so that //the active state picks up from there. DO NOT REMOVE THIS LINE. //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND //WILL TAKE YEARS AWAY FROM YOUR LIFE. var width = bod.offsetWidth + 1; // we use a for loop to ensure that if the queue is changed // during this looping then it will consider new requests for (var i = 0; i < rafWaitQueue.length; i++) { rafWaitQueue[i](width); } rafWaitQueue.length = 0; }); } return init; function computeTimings(node, className, cacheKey) { var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES); var aD = timings.animationDelay; var tD = timings.transitionDelay; timings.maxDelay = aD && tD ? Math.max(aD, tD) : (aD || tD); timings.maxDuration = Math.max( timings.animationDuration * timings.animationIterationCount, timings.transitionDuration); return timings; } function init(element, options) { var node = getDomNode(element); options = prepareAnimationOptions(options); var temporaryStyles = []; var classes = element.attr('class'); var styles = packageStyles(options); var animationClosed; var animationPaused; var animationCompleted; var runner; var runnerHost; var maxDelay; var maxDelayTime; var maxDuration; var maxDurationTime; if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) { return closeAndReturnNoopAnimator(); } var method = options.event && isArray(options.event) ? options.event.join(' ') : options.event; var isStructural = method && options.structural; var structuralClassName = ''; var addRemoveClassName = ''; if (isStructural) { structuralClassName = pendClasses(method, 'ng-', true); } else if (method) { structuralClassName = method; } if (options.addClass) { addRemoveClassName += pendClasses(options.addClass, '-add'); } if (options.removeClass) { if (addRemoveClassName.length) { addRemoveClassName += ' '; } addRemoveClassName += pendClasses(options.removeClass, '-remove'); } // there may be a situation where a structural animation is combined together // with CSS classes that need to resolve before the animation is computed. // However this means that there is no explicit CSS code to block the animation // from happening (by setting 0s none in the class name). If this is the case // we need to apply the classes before the first rAF so we know to continue if // there actually is a detected transition or keyframe animation if (options.applyClassesEarly && addRemoveClassName.length) { applyAnimationClasses(element, options); addRemoveClassName = ''; } var setupClasses = [structuralClassName, addRemoveClassName].join(' ').trim(); var fullClassName = classes + ' ' + setupClasses; var activeClasses = pendClasses(setupClasses, '-active'); var hasToStyles = styles.to && Object.keys(styles.to).length > 0; // there is no way we can trigger an animation since no styles and // no classes are being applied which would then trigger a transition if (!hasToStyles && !setupClasses) { return closeAndReturnNoopAnimator(); } var cacheKey, stagger; if (options.stagger > 0) { var staggerVal = parseFloat(options.stagger); stagger = { transitionDelay: staggerVal, animationDelay: staggerVal, transitionDuration: 0, animationDuration: 0 }; } else { cacheKey = gcsHashFn(node, fullClassName); stagger = computeCachedCssStaggerStyles(node, setupClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES); } $$jqLite.addClass(element, setupClasses); var applyOnlyDuration; if (options.transitionStyle) { var transitionStyle = [TRANSITION_PROP, options.transitionStyle]; applyInlineStyle(node, transitionStyle); temporaryStyles.push(transitionStyle); } if (options.duration >= 0) { applyOnlyDuration = node.style[TRANSITION_PROP].length > 0; var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration); // we set the duration so that it will be picked up by getComputedStyle later applyInlineStyle(node, durationStyle); temporaryStyles.push(durationStyle); } if (options.keyframeStyle) { var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle]; applyInlineStyle(node, keyframeStyle); temporaryStyles.push(keyframeStyle); } var itemIndex = stagger ? options.staggerIndex >= 0 ? options.staggerIndex : gcsLookup.count(cacheKey) : 0; var isFirst = itemIndex === 0; // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY // without causing any combination of transitions to kick in. By adding a negative delay value // it forces the setup class' transition to end immediately. We later then remove the negative // transition delay to allow for the transition to naturally do it's thing. The beauty here is // that if there is no transition defined then nothing will happen and this will also allow // other transitions to be stacked on top of each other without any chopping them out. if (isFirst) { blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE); } var timings = computeTimings(node, fullClassName, cacheKey); var relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; var flags = {}; flags.hasTransitions = timings.transitionDuration > 0; flags.hasAnimations = timings.animationDuration > 0; flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all'; flags.applyTransitionDuration = hasToStyles && ( (flags.hasTransitions && !flags.hasTransitionAll) || (flags.hasAnimations && !flags.hasTransitions)); flags.applyAnimationDuration = options.duration && flags.hasAnimations; flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions); flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations; flags.recalculateTimingStyles = addRemoveClassName.length > 0; if (flags.applyTransitionDuration || flags.applyAnimationDuration) { maxDuration = options.duration ? parseFloat(options.duration) : maxDuration; if (flags.applyTransitionDuration) { flags.hasTransitions = true; timings.transitionDuration = maxDuration; applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0; temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration)); } if (flags.applyAnimationDuration) { flags.hasAnimations = true; timings.animationDuration = maxDuration; temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration)); } } if (maxDuration === 0 && !flags.recalculateTimingStyles) { return closeAndReturnNoopAnimator(); } // we need to recalculate the delay value since we used a pre-emptive negative // delay value and the delay value is required for the final event checking. This // property will ensure that this will happen after the RAF phase has passed. if (options.duration == null && timings.transitionDuration > 0) { flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst; } maxDelayTime = maxDelay * ONE_SECOND; maxDurationTime = maxDuration * ONE_SECOND; if (!options.skipBlocking) { flags.blockTransition = timings.transitionDuration > 0; flags.blockKeyframeAnimation = timings.animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0; } applyAnimationFromStyles(element, options); if (!flags.blockTransition) { blockTransitions(node, false); } applyBlocking(maxDuration); // TODO(matsko): for 1.5 change this code to have an animator object for better debugging return { $$willAnimate: true, end: endFn, start: function() { if (animationClosed) return; runnerHost = { end: endFn, cancel: cancelFn, resume: null, //this will be set during the start() phase pause: null }; runner = new $$AnimateRunner(runnerHost); waitUntilQuiet(start); // we don't have access to pause/resume the animation // since it hasn't run yet. AnimateRunner will therefore // set noop functions for resume and pause and they will // later be overridden once the animation is triggered return runner; } }; function endFn() { close(); } function cancelFn() { close(true); } function close(rejected) { // jshint ignore:line // if the promise has been called already then we shouldn't close // the animation again if (animationClosed || (animationCompleted && animationPaused)) return; animationClosed = true; animationPaused = false; $$jqLite.removeClass(element, setupClasses); $$jqLite.removeClass(element, activeClasses); blockKeyframeAnimations(node, false); blockTransitions(node, false); forEach(temporaryStyles, function(entry) { // There is only one way to remove inline style properties entirely from elements. // By using `removeProperty` this works, but we need to convert camel-cased CSS // styles down to hyphenated values. node.style[entry[0]] = ''; }); applyAnimationClasses(element, options); applyAnimationStyles(element, options); // the reason why we have this option is to allow a synchronous closing callback // that is fired as SOON as the animation ends (when the CSS is removed) or if // the animation never takes off at all. A good example is a leave animation since // the element must be removed just after the animation is over or else the element // will appear on screen for one animation frame causing an overbearing flicker. if (options.onDone) { options.onDone(); } // if the preparation function fails then the promise is not setup if (runner) { runner.complete(!rejected); } } function applyBlocking(duration) { if (flags.blockTransition) { blockTransitions(node, duration); } if (flags.blockKeyframeAnimation) { blockKeyframeAnimations(node, !!duration); } } function closeAndReturnNoopAnimator() { runner = new $$AnimateRunner({ end: endFn, cancel: cancelFn }); close(); return { $$willAnimate: false, start: function() { return runner; }, end: endFn }; } function start() { if (animationClosed) return; var startTime, events = []; // even though we only pause keyframe animations here the pause flag // will still happen when transitions are used. Only the transition will // not be paused since that is not possible. If the animation ends when // paused then it will not complete until unpaused or cancelled. var playPause = function(playAnimation) { if (!animationCompleted) { animationPaused = !playAnimation; if (timings.animationDuration) { var value = blockKeyframeAnimations(node, animationPaused); animationPaused ? temporaryStyles.push(value) : removeFromArray(temporaryStyles, value); } } else if (animationPaused && playAnimation) { animationPaused = false; close(); } }; // checking the stagger duration prevents an accidently cascade of the CSS delay style // being inherited from the parent. If the transition duration is zero then we can safely // rely that the delay value is an intential stagger delay style. var maxStagger = itemIndex > 0 && ((timings.transitionDuration && stagger.transitionDuration === 0) || (timings.animationDuration && stagger.animationDuration === 0)) && Math.max(stagger.animationDelay, stagger.transitionDelay); if (maxStagger) { $timeout(triggerAnimationStart, Math.floor(maxStagger * itemIndex * ONE_SECOND), false); } else { triggerAnimationStart(); } // this will decorate the existing promise runner with pause/resume methods runnerHost.resume = function() { playPause(true); }; runnerHost.pause = function() { playPause(false); }; function triggerAnimationStart() { // just incase a stagger animation kicks in when the animation // itself was cancelled entirely if (animationClosed) return; applyBlocking(false); forEach(temporaryStyles, function(entry) { var key = entry[0]; var value = entry[1]; node.style[key] = value; }); applyAnimationClasses(element, options); $$jqLite.addClass(element, activeClasses); if (flags.recalculateTimingStyles) { fullClassName = node.className + ' ' + setupClasses; cacheKey = gcsHashFn(node, fullClassName); timings = computeTimings(node, fullClassName, cacheKey); relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; if (maxDuration === 0) { close(); return; } flags.hasTransitions = timings.transitionDuration > 0; flags.hasAnimations = timings.animationDuration > 0; } if (flags.applyTransitionDelay || flags.applyAnimationDelay) { relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay) ? parseFloat(options.delay) : relativeDelay; maxDelay = Math.max(relativeDelay, 0); var delayStyle; if (flags.applyTransitionDelay) { timings.transitionDelay = relativeDelay; delayStyle = getCssDelayStyle(relativeDelay); temporaryStyles.push(delayStyle); node.style[delayStyle[0]] = delayStyle[1]; } if (flags.applyAnimationDelay) { timings.animationDelay = relativeDelay; delayStyle = getCssDelayStyle(relativeDelay, true); temporaryStyles.push(delayStyle); node.style[delayStyle[0]] = delayStyle[1]; } } maxDelayTime = maxDelay * ONE_SECOND; maxDurationTime = maxDuration * ONE_SECOND; if (options.easing) { var easeProp, easeVal = options.easing; if (flags.hasTransitions) { easeProp = TRANSITION_PROP + TIMING_KEY; temporaryStyles.push([easeProp, easeVal]); node.style[easeProp] = easeVal; } if (flags.hasAnimations) { easeProp = ANIMATION_PROP + TIMING_KEY; temporaryStyles.push([easeProp, easeVal]); node.style[easeProp] = easeVal; } } if (timings.transitionDuration) { events.push(TRANSITIONEND_EVENT); } if (timings.animationDuration) { events.push(ANIMATIONEND_EVENT); } startTime = Date.now(); element.on(events.join(' '), onAnimationProgress); $timeout(onAnimationExpired, maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime); applyAnimationToStyles(element, options); } function onAnimationExpired() { // although an expired animation is a failed animation, getting to // this outcome is very easy if the CSS code screws up. Therefore we // should still continue normally as if the animation completed correctly. close(); } function onAnimationProgress(event) { event.stopPropagation(); var ev = event.originalEvent || event; var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); /* Firefox (or possibly just Gecko) likes to not round values up * when a ms measurement is used for the animation */ var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)); /* $manualTimeStamp is a mocked timeStamp value which is set * within browserTrigger(). This is only here so that tests can * mock animations properly. Real events fallback to event.timeStamp, * or, if they don't, then a timeStamp is automatically created for them. * We're checking to see if the timeStamp surpasses the expected delay, * but we're using elapsedTime instead of the timeStamp on the 2nd * pre-condition since animations sometimes close off early */ if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) { // we set this flag to ensure that if the transition is paused then, when resumed, // the animation will automatically close itself since transitions cannot be paused. animationCompleted = true; close(); } } } } }]; }];


|
MetaDrone
2.0
|
Provides the properties used to access the information in a WebSocket connection request received by the TcpListener. More...
Public Member Functions | |
| override string | ToString () |
| Returns a string that represents the current TcpListenerWebSocketContext. More... | |
Properties | |
| override CookieCollection | CookieCollection [get] |
| Gets the HTTP cookies included in the request. More... | |
| override NameValueCollection | Headers [get] |
| Gets the HTTP headers included in the request. More... | |
| override string | Host [get] |
| Gets the value of the Host header included in the request. More... | |
| override bool | IsAuthenticated [get] |
| Gets a value indicating whether the client is authenticated. More... | |
| override bool | IsLocal [get] |
| Gets a value indicating whether the client connected from the local computer. More... | |
| override bool | IsSecureConnection [get] |
| Gets a value indicating whether the WebSocket connection is secured. More... | |
| override bool | IsWebSocketRequest [get] |
| Gets a value indicating whether the request is a WebSocket connection request. More... | |
| override string | Origin [get] |
| Gets the value of the Origin header included in the request. More... | |
| override NameValueCollection | QueryString [get] |
| Gets the query string included in the request. More... | |
| override Uri | RequestUri [get] |
| Gets the URI requested by the client. More... | |
| override string | SecWebSocketKey [get] |
| Gets the value of the Sec-WebSocket-Key header included in the request. More... | |
| override IEnumerable< string > | SecWebSocketProtocols [get] |
| Gets the values of the Sec-WebSocket-Protocol header included in the request. More... | |
| override string | SecWebSocketVersion [get] |
| Gets the value of the Sec-WebSocket-Version header included in the request. More... | |
| override System.Net.IPEndPoint | ServerEndPoint [get] |
| Gets the server endpoint as an IP address and a port number. More... | |
| override IPrincipal | User [get] |
| Gets the client information (identity, authentication, and security roles). More... | |
| override System.Net.IPEndPoint | UserEndPoint [get] |
| Gets the client endpoint as an IP address and a port number. More... | |
| override WebSocket | WebSocket [get] |
| Gets the WebSocketSharp.WebSocket instance used for two-way communication between client and server. More... | |
| Properties inherited from WebSocketSharp.Net.WebSockets.WebSocketContext | |
| abstract CookieCollection | CookieCollection [get] |
| Gets the HTTP cookies included in the request. More... | |
| abstract NameValueCollection | Headers [get] |
| Gets the HTTP headers included in the request. More... | |
| abstract string | Host [get] |
| Gets the value of the Host header included in the request. More... | |
| abstract bool | IsAuthenticated [get] |
| Gets a value indicating whether the client is authenticated. More... | |
| abstract bool | IsLocal [get] |
| Gets a value indicating whether the client connected from the local computer. More... | |
| abstract bool | IsSecureConnection [get] |
| Gets a value indicating whether the WebSocket connection is secured. More... | |
| abstract bool | IsWebSocketRequest [get] |
| Gets a value indicating whether the request is a WebSocket connection request. More... | |
| abstract string | Origin [get] |
| Gets the value of the Origin header included in the request. More... | |
| abstract NameValueCollection | QueryString [get] |
| Gets the query string included in the request. More... | |
| abstract Uri | RequestUri [get] |
| Gets the URI requested by the client. More... | |
| abstract string | SecWebSocketKey [get] |
| Gets the value of the Sec-WebSocket-Key header included in the request. More... | |
| abstract IEnumerable< string > | SecWebSocketProtocols [get] |
| Gets the values of the Sec-WebSocket-Protocol header included in the request. More... | |
| abstract string | SecWebSocketVersion [get] |
| Gets the value of the Sec-WebSocket-Version header included in the request. More... | |
| abstract System.Net.IPEndPoint | ServerEndPoint [get] |
| Gets the server endpoint as an IP address and a port number. More... | |
| abstract IPrincipal | User [get] |
| Gets the client information (identity, authentication, and security roles). More... | |
| abstract System.Net.IPEndPoint | UserEndPoint [get] |
| Gets the client endpoint as an IP address and a port number. More... | |
| abstract WebSocket | WebSocket [get] |
| Gets the WebSocketSharp.WebSocket instance used for two-way communication between client and server. More... | |
Additional Inherited Members | |
| Protected Member Functions inherited from WebSocketSharp.Net.WebSockets.WebSocketContext | |
| WebSocketContext () | |
| Initializes a new instance of the WebSocketContext class. More... | |
Provides the properties used to access the information in a WebSocket connection request received by the TcpListener.
| override string WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext.ToString | ( | ) |
Returns a string that represents the current TcpListenerWebSocketContext.
|
get |
Gets the HTTP cookies included in the request.
A WebSocketSharp.Net.CookieCollection that contains the cookies.
|
get |
Gets the HTTP headers included in the request.
A NameValueCollection that contains the headers.
|
get |
Gets the value of the Host header included in the request.
A string that represents the value of the Host header.
|
get |
Gets a value indicating whether the client is authenticated.
true
if the client is authenticated; otherwise, false
.
|
get |
Gets a value indicating whether the client connected from the local computer.
true
if the client connected from the local computer; otherwise, false
.
|
get |
Gets a value indicating whether the WebSocket connection is secured.
true
if the connection is secured; otherwise, false
.
|
get |
|
get |
Gets the value of the Origin header included in the request.
A string that represents the value of the Origin header.
|
get |
Gets the query string included in the request.
A NameValueCollection that contains the query string parameters.
|
get |
Gets the URI requested by the client.
A Uri that represents the requested URI.
|
get |
Gets the value of the Sec-WebSocket-Key header included in the request.
This property provides a part of the information used by the server to prove that it received a valid WebSocket connection request.
A string that represents the value of the Sec-WebSocket-Key header.
|
get |
Gets the values of the Sec-WebSocket-Protocol header included in the request.
This property represents the subprotocols requested by the client.
An T:System.Collections.Generic.IEnumerable<string> instance that provides an enumerator which supports the iteration over the values of the Sec-WebSocket-Protocol header.
|
get |
Gets the value of the Sec-WebSocket-Version header included in the request.
This property represents the WebSocket protocol version.
A string that represents the value of the Sec-WebSocket-Version header.
|
get |
Gets the server endpoint as an IP address and a port number.
A System.Net.IPEndPoint that represents the server endpoint.
|
get |
Gets the client information (identity, authentication, and security roles).
A IPrincipal that represents the client information.
|
get |
Gets the client endpoint as an IP address and a port number.
A System.Net.IPEndPoint that represents the client endpoint.
|
get |
Gets the WebSocketSharp.WebSocket instance used for two-way communication between client and server.


A website (also written as web site) is a collection of web pages and related content that is identified by a common domain name and published on at least one web server. Notable examples are wikipedia.org, google.com, and amazon.com. All publicly accessible websites collectively constitute the World Wide Web. There are also private websites that can only be accessed on a private network, such as a company's internal website for its employees. Websites are typically dedicated to a particular topic or purpose, such as news, education, commerce, entertainment, or social networking. Hyperlinking between web pages guides the navigation of the site, which often starts with a home page. Users can access websites on a range of devices, including desktops, laptops, tablets, and smartphones. The software application used on these devices is called a web browser.


{% extends 'base.html' %} {% block page_title %}Forgot Your Password?{% endblock %} {% block page_content %}
Enter your email address below, and we'll email instructions for setting a new one.


Straight Garbage
Home
About
Disposal Location
Home
About
Disposal Location
menu
We would love to hear from you!
Feel free to reach out to us with any recycing questions or comments, we always love hearing from other humans.
Reach out with any questions or concerns, or just say hi!
Email us today


Alyson & Kyle Wooderson
Our Wedding Details
Dress
Formal, black tie optional (suit and tie and dresses)
RSVP
Please RSVP before August 20th, 2020.
Send all responses by clicking here.
Where to Stay
You may request a hotel reservation in the RSVP form below.
Contact Us
Click here to contact us directly, otherwise please fill out the form to let us know if you will be attending.


Letters from the trenches provide poignant reminder of Canadian soldiers' sacrifice
by Kevin Gallagher, Parliament Hill Correspondent, CTV National News Cillian O'Brien, CTVNews.ca WriterTORONTO -- A remembrance project in Ottawa has honoured the sacrifice of Canadian soldiers on the front lines through their letters to loved ones back home.
“Letters In a Time Of War” at The Canadian War Museum sees wartime correspondence from more than 20 soldiers read aloud by actors, students, relatives and others, accompanied by live music.
One such soldier was Maj. John Archibald “Archie” MacNaughton of New Brunswick, who fought in the First and Second World War.
Maj. MacNaughton had no way of knowing that mail to his wife and children dated June 4, 1944 and read by Meriel Bradford for the letters project, would be his last. He was killed on the beaches of Normandy two days later.
“No matter how things go Grace, life has been very kind to us,” Maj. MacNaughton of the North Shore Regiment wrote aged 47.
“I have had many pleasures to look on. All has been very pleasant.”
The soldier led his hometown regiment onto Juno Beach as part of the Allied invasion of Nazi-occupied France in the D-Day landings on June 6, a story recounted in a Heritage Minute.
“Fancie and Margie, take care take care of mumser,” he wrote.
For Bradford, the readings are touching and personal. Her father, Brig.-Gen. Ted Beament helped plan the invasion that saw the beginning of the end of the Second World War.
“I think he wanted them to know that it was an important thing he was going to be doing and that he loved them,” Bradford told CTV News Ottawa while fighting back tears.
“And that he was doing it for his country. So yes my dad had all this complexity to deal with and Archie was at the sharp end and had to actually deliver.”
The creators of the project hope it will honour many more Canadian war heroes in the future.
“Even though we are commemorating an act of remembrance and we’re discussing war and conflict, I think the theme that weaves its way through almost every single letter we read is love,” co-creator David Henderson told CTV News Ottawa.
Maj. MacNaughton made a promise to his family in his last letter home.
“Goodnight dear people, I will tell you one day where I wrote this letter,” he wrote.
“All my love to you and may God take care of you all. As ever, Archie.”


1. Which of the following is correct about features of Javascript?
2. Which of the following is the correct syntax to print a page using Javascript?
3. Which built-in method calls a function for each element in the array?
4. Which of the following function of string object splits a string object into an array of strings by separating the string into substrings?
5. Which of the following function of Array object creates a new array with the results of calling a provided function on every element in this array?


Delete broken metadata file from groups or remote repositories.
(Can be a full or a relative url like "/api/content/maven/group/central/org/foo/bar/maven-metadata.xml. Be noticed that this will trigger the deletions of the target path from all affected groups.")


|
BL3 SDK
0.0.1
Borderlands 3 Class Documentation
|
#include <BL3_Engine_structs.hpp>
Public Attributes | |
| unsigned char | bBlockingHit: 1 |
| unsigned char | bStartPenetrating: 1 |
| unsigned char | UnknownData00 [0x3] |
| int | FaceIndex |
| unsigned char | bLagCompensated: 1 |
| unsigned char | UnknownData01 [0x3] |
| float | Time |
| float | Distance |
| struct FVector_NetQuantize | Location |
| struct FVector_NetQuantize | ImpactPoint |
| struct FVector_NetQuantizeNormal | Normal |
| struct FVector_NetQuantizeNormal | ImpactNormal |
| struct FVector_NetQuantize | TraceStart |
| struct FVector_NetQuantize | TraceEnd |
| float | PenetrationDepth |
| int | Item |
| TWeakObjectPtr< class UPhysicalMaterial > | PhysMaterial |
| TWeakObjectPtr< class AActor > | Actor |
| TWeakObjectPtr< class UPrimitiveComponent > | Component |
| unsigned char | UnknownData02 [0x4] |
| struct FName | BoneName |
| struct FName | MyBoneName |
| TWeakObjectPtr<class AActor> Actor |
| unsigned char bBlockingHit |
| unsigned char bLagCompensated |
| struct FName BoneName |
| unsigned char bStartPenetrating |
| TWeakObjectPtr<class UPrimitiveComponent> Component |
| float Distance |
| int FaceIndex |
| struct FVector_NetQuantizeNormal ImpactNormal |
| struct FVector_NetQuantize ImpactPoint |
| int Item |
| struct FVector_NetQuantize Location |
| struct FName MyBoneName |
| struct FVector_NetQuantizeNormal Normal |
| float PenetrationDepth |
| TWeakObjectPtr<class UPhysicalMaterial> PhysMaterial |
| float Time |
| struct FVector_NetQuantize TraceEnd |
| struct FVector_NetQuantize TraceStart |
| unsigned char UnknownData00[0x3] |
| unsigned char UnknownData01[0x3] |
| unsigned char UnknownData02[0x4] |


--- layout: post title: Web and native client add-in categories: [] tags: web-client dotnet-sdk status: publish type: post published: true meta: {} ---
Many customers and partners are familiar with extending ITrimAddIn in the RM SDK to create a native client add-in and in 83 record addon was added to the web client. This sample looks at one approach to maintaining paralell addons in the native and web client.
Here is the code:


the server end's code like:
import os import socket host = '<IP_ADDRESS>' port = 7000 buffer_size = 1024 listen_number = 5 http_socket = socket.socket() http_socket.bind((host,port)) http_socket.listen(listen_number) while True: sock,address = http_socket.accept() print("get accept from address:",address) req = sock.recv(buffer_size) print("get requests:");print("=========================") print(req.decode('utf-8')) print("=========================") with open(os.path.join(os.path.dirname(__file__),"t_res.txt"),"rb") as fh: res = fh.read() sock.send(res) print("send response finished") sock.close() http_socket.close()
The client end's code like:
import os import socket host = '<IP_ADDRESS>' port = 7000 buffer_size = 1024 http_socket = socket.socket() http_socket.connect_ex((host,port)) with open(os.path.join(os.path.dirname(__file__),"t_req.txt"),"rb") as fh: http_socket.send(fh.read()) data = http_socket.recv(buffer_size) print("get data:");print("------------------------") print(data.decode('utf-8'));print("------------------------")
the baidu's response like:
HTTP/1.1 302 Found Cache-Control: max-age=86400 Connection: Keep-Alive Content-Length: 222 Content-Type: text/html; charset=iso-8859-1 Date: Sat, 08 Jun 2019 10:19:34 GMT Expires: Sun, 09 Jun 2019 10:19:34 GMT Location: https://www.baidu.com/search/error.html Server: Apache302 Found Found
The document has moved here.
the mozilla request header like:
GET / HTTP/1.1 Host: <IP_ADDRESS>:7000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1
the chrome mini request header like:
GET / HTTP/1.1 Host: <IP_ADDRESS>:7000 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9


[gecode-users] GIST
Guido Tack
tack at gecode.org
Wed Mar 31 10:06:34 CEST 2010
Hi,
the exports were indeed wrong. I fixed it in the Gecode svn trunk, it will be part of the next release. I also added a small example that shows how to embed the Gist widget in your own Qt code.
Gist currently depends on Gecode, but it should be possible to replace the Gecode-specific parts. One way of doing that would be to mimic Gecode's Space interface, i.e. implement your own Space class that has the same methods and works similarly. I think then you would just need to remove the use of dfs in SpaceNode and TreeCanvas (they are only necessary for subtle recomputation issues related to Gecode internals). Alternatively, you could reimplement SpaceNode to match your solver, and adapt all references to spaces from the remaining code (but I guess that's more work).
We usually only make parts of Gecode more generic if someone uses that genericity. So if you need a more generic Gist and run into problems with the current design, please let us know!
Cheers,
Guido
Tripti Saxena wrote:
> Hello,
>
> I have written a small solver in C++ and I was wondering if I can use Gist to visual the search tree produced by the my solver. In other words is it possible to use Gist independent of Gecode ? The basic interface provided by Gist is good but I will have to make extension specific to my solver.
>
> Has anyone tried this before. I read the manual and created a QT application where I was trying to include Gist as a widget. Although the manual says it is possible, I kept getting linker errors because the class definitions (GistMainWindow) is not exported. Is there a way around it or maybe there is something I am missing out.
>
>
> Thanks in advance.
>
>
> Tripti
> _______________________________________________
> Gecode users mailing list
> users at gecode.org
> https://www.gecode.org/mailman/listinfo/gecode-users
More information about the users
mailing list


They are known for their unique naming system which is based on the day of the week a child is born and they vary for both genders.
Children are thus given their first name depending on the particular day they were born.
This naming system is shared throughout West Africa and the African diaspora.
The data form below outputs your Akan name upon inserting birth details correctly.


Portable distribution of operating systems and tools
A sparvk portable operating system distribution comes with a very nifty feature that allows you to use a single installation with multiple users. Such that:-
Each user will have their own directory that keeps the work data separate from all other users. This is a logical separation. Only the ad...
Sparvk enabled filesystem allows you to connect to your remote servers. WIth this functionality you can perform operations on network files and directories easily.
Here's how you can connect to a network file system.
Navigate to the computer tab and choose the network option from your star...
Most of the computer applications that you use on a daily basis store their data in files. Programs for making documents, sheets, presentations they all have their own files. How their files are created and how the data is stored is specific to a particular program but they all store data in files....
GNU cash is a powerful opensource accounting software that can help you keep books and track your taxes/loans and mortgages. From the website
“GnuCash is a personal and small-business financial-accounting software, freely licensed under the GPL. Designed to be easy to use, yet powerful and f...
Gnucash free accounting software allows you to create invoices for your customers. For the purposes of this tutorial we'll create a new business account. Start gnucash and navigate to file new file. Proceed through the steps in the wizard. On the create account screen make sure that you choose a bu...


--- title: "Student Data Management App" caption: "/img/caption-rentree.png" date: 2009-08-30 ---
Back in 2009, I created a web application to handle the BDE suscriptions of students (about 400 each year),
and to manage data such as phone numbers, address, etc.
No framework were used, I did all the code (backend and frontend) myself.
The use of this app saved us a lot of time and the overall management of the association was greatly improved.


ProHits-viz was initially designed for the visualization of protein-protein interaction data, but it has always been able to visualize any tabular data that conforms to our generic input format. This format requires four parameters for each data point:
Many common proteomic and genomic experiments will generate data consistent with this format, or can be easily converted to it, and can thus benefit from the visualization tools we provide.
To date, we have only provided explicit support for the output from two protein-protein interaction analysis tools: 1) SAINT and 2) CRAPome/REPRINT. Data output from other tools, whether from protein-protein interaction studies or some other experiment type, have required conversion by the user to conform with our input format.
We are aiming to provide more direct support for the outputs from various analysis pipelines, allowing seamless integration with ProHits-viz, as we seek to make it as simple as possible for users to benefit from our tools. To this end, we have now added explicit support for the visualization of data output from common analysis tools that handle CRISPR experiments. These include:
The metric to visualize from these tools typically takes both positive and negative values, for example a Z-score or log2 fold change. Previously we required the “abundance” value to be visualized to only take non-negative values, but all of our tools have now been updated to support negative values as well. In some cases these values get treated as absolute/positive values, for example when calculating the dot size ratio on dot plots: a dot of -10 and +10 will be the same size; or when applying filters: a filter of 1 will now filter anything between -1 and 1, rather than just from 0 to 1. Otherwise visualization should be intuitive and as expected.
The first step in using CRISPR data at ProHits-viz is to go to our utilities page and select the files you would like to analyze. You can select as many files as you would like. Then select the option “Convert output from a CRISPR analysis tool to a ProHits-viz compatible format” and the tool that produced the files. Hitting submit will return a single file containing all of the input analyses formatted for ProHits-viz. It is important to note that BAGEL, drugZ and RANKS analyze a single experiment at a time, and so if you wish to compare the results from multiple experiments, you must select all of the relevant files at the input stage.
With the conversion complete, you can head to the analysis page, input the converted file and file type, and ProHits-viz will automatically select suitable options from here onwards for any type of analysis you would like to perform.


I am a Software Developer from Souther California. I am passionate about programming and a fast learner. I have experiences with web development, machine learning algorithm, data fusion and data science. With my career begin in Defense and Aerospace industry, I am experienced in Mission Planning software and process, and Electronic Warfare. I currently hold DoD Secret Clearance.
Responsible and accountable for test and analysis plans and coordination, instrumentation requirements coordination, pre-test predictions, test procedure development & methods, test data management and validation, first pass post-test data analysis and test reporting and documentation for GPS Software tests and functional validation.
Short term contract works entailed intergrating a revamped backend software that manages users in a financial book software, strengthen the integrity of the data and its interfaces.
Developed software that can do data processing and correlation, binary decoding, and postflight analysis for Navy pilots and mission data analysts.
Deployed Deep Learning and intergrate into a image recognition web application for military use.
Worked on documentation, system engineering, and program coordinator for F/A 18 Legacy program.
Developed front end website for internal business tools such as aircraft logistic and comptroller web tools.
Taught middle school students engineering concept in an afterschool program and guided the students toward engineering career.
More info here.Train computer to play Super Mario Bros.
A portfolio website of an event planner.
A topdown shooter game developed on Unity.
Developed an image classifier using Matlab.
Deliver an event web page for a non-profit organization.
Using Java to scrape texts from Google's search result and store in local folder, used to train NLP model
President of Vietnamese Student Association Club
Reinforcement Learning
Game Development
Linux
Web Development
Data Science
Machine Learning
Pattern Recognition
Image Processing
Neural Network
Human Computer Interaction
Agile in Software Engineering
Mission Planning in Electronic Warfare
Full stack development
DevOps
Object Oriented Programming
Binary data


Latest talks
{% if object_list %}
{% include "_partials/pagination.html" with url_target='talks:latest-talks-paginated' %}
{% include "_partials/list_talks.html" %}
{% include "_partials/pagination.html" with url_target='talks:latest-talks-paginated' %}
{% else %}
No results.
{% endif %}


| Path: | lib/active_merchant/billing/gateways/psigate.rb |
| Last Update: | Sun Nov 23 12:09:43 -0800 2008 |
This class implements the Psigate gateway for the ActiveMerchant module. Psigate = www.psigate.com/ The class is currently set up to use the psigate test server while rails is in testing or developement mode. The real server will be used while in production mode.
Modifications by Sean O‘Hara ( sohara at sohara dot com )
Usage for a PreAuth (authorize) is as follows:
twenty = 2000 gateway = PsigateGateway.new(
:login => 'teststore', :password => 'psigate1234'
)
creditcard = CreditCard.new(
:number => '4242424242424242', :month => 8, :year => 2006, :first_name => 'Longbob', :last_name => 'Longsen'
) response = @gateway.authorize(twenty, creditcard,
:order_id => 1234, :billing_address => { :address1 => '123 fairweather Lane', :address2 => 'Apt B', :city => 'New York', :state => 'NY', :country => 'U.S.A.', :zip => '10010' }, :email =><EMAIL_ADDRESS>)


There's a discussion going on about women and IT, starting with a post by Richard Jones: Why there's few women in IT. Phillip Eby responded in Is porn driving women away from the computer industry?, The Real Reasons There Are Few Women In IT -- And What YOU Can Do About It and Why (Most) Men Don't Get It -- and I personally find his analysis much more useful.
Richard's original post talks about a case where someone used porn in a presentation, and he's basically saying that is "why there's few women in IT". I don't buy it.
First: is anyone claiming that IT as a field is more discriminatory than other fields? I don't think that's the case, despite the fact that the gender balance is worse than many other fields. Therefore I don't think this particular anecdote points to a larger problem specific to the community, nor does it explain the gender imbalance in the field, nor does it point to solutions.
Second: we have to accept each other as whole people; with the greater transparency of the internet we have to adapt our expectations and recognize people have lives that are larger than just the one aspect we would normally see in professional settings. Using pornography in a presentation at a conference of course isn't appropriate, but something like Acme::Playmate is not inappropriate in any way. Phillip is right to call the nature of the response patronizing. What are people trying to say? That women do not realize that Playboy exists? Are we trying to create a world where you can be completely insulated from pornography? To try to create or enable such a worldview is unreasonable and insulting to everyone's intelligence. We do not need to eliminate all sexual expressions from our community.
Third: the Free/Open Source community is not a professional community. Many participants do not participate professionally, or participate both as professionals and as hobbyists. Someone wanted to be able to grab playmate metadata easily... for what reason I'm actually not sure; to graph changes in average measurements over time? It doesn't really matter; the author doesn't need to justify it, and CPAN doesn't need to justify why it lists it (in fact there's little reason for either -- it exists, therefore CPAN lists it).
We should generally be careful about creating hostile environments -- hostile towards anyone. This is something that needs to be constantly considered, but is best dealt with person-to-person, and in response to specific situations. If our communities are so fragile that we cannot deal with an occasional mistake, then we've already lost. Of course you still need to correct mistakes; the quality of the response should be the judge of a community, especially open communities like F/OSS communities.
We should not try to protect our communities by limiting our expression to what is considered appropriate in a professional environment. We should not limit our expression to those things that are appropriate for female ears or eyes -- and of course the very phrase is discriminatory! But that's the sentiment underlying Richard's original post.
This post doesn't offer any constructive suggestions about what to do about the gender imbalance. That's a much harder question. I just don't think focusing on discrimination is the right line of thought. I think it's the easy line of thought -- that if we just stop discriminating and stop creating a hostile environments we'll see more women. Following that path will create a chilling effect on personal expression and will hurt our community. Of this I am confident, because I and everyone else here knows what professional communication styles are like -- they are dull and disingenuous -- and that is exactly what people are calling for by making general arguments based on this one ill-considered presentation.
(If you read through the comments on that post, and PJE's posts, you'll see a wider discussion than just this one issue -- but it's not fair to fold all those ideas together into one response)
Heh, the ads at the moment include two ads for lawyers specializing in sexual harassment, and one ad to increase your libido. Sex and gender make for odd bedfellows. Pun obviously intended, many apologies.
# Ian Bicking
Oh, and another anecdote: in the comments on Richard's post a guy actually says that in the U.S. the proper response to someone putting up porn at a conference would be to call up the police and have the presenter arrested.  Still I found it disturbing that someone would even suggest such a thing.
Second, lots of people seemed offended that lots of people didn't immediately walk out of the presentation (which was itself just a lightning talk, so there wouldn't have been much to walk out on). I can't imagine they understand the social dynamics involved. They seemed to feel the presenter was, of course, disrespecting all women by using that image. Well, I can't say exactly what his intentions were, but I bet it was to get a quick laugh, and to make a comment on the underlying motivations of certain open source contributors. Do they really think he was trying to be exclusionary? That he was trying to offend or harass? That's not to say that some women didn't feel excluded or offended by it, but there's a difference between a mistake and a deliberate act. Mistakes should not be dealt with through exclusion, which is all that would have been accomplished through walking out. They should be dealt with by directly communicating any disappointment, and publicly clarifying what is appropriate. But that one guy's mistake shouldn't make him the symbol for all discrimination.
Lastly, people complained about things like people having provocative backgrounds on their laptops. And maybe they were right. But are they saying that those people shouldn't be allowed to have such backgrounds on their laptops at all? If they are allowed to have such backgrounds, one can only expect that some people won't think to change them before attaching their laptop to the projector.  This is the nature of our leaky personal boundaries, and I do not accept people being accusatory simply because they see a confirmation that their fellow humans also are sexual beings.  (It's unclear to me if there were actually women who were offended or excluded by these unintentional images; I doubt it.)
Anyway, I realize I didn't provide a lot of context for why the responses there bothered me, and maybe this is a little more context.
 And maybe they were right. But are they saying that those people shouldn't be allowed to have such backgrounds on their laptops at all? If they are allowed to have such backgrounds, one can only expect that some people won't think to change them before attaching their laptop to the projector."
Since I made that comment, I'll elucidate: when conducting public business you have to behave in an appropriate fashion. No-one is saying that people shouldn't enjoy their favourite erotic desktop backgrounds: I'm just saying that people should consider that their own attitudes may differ from others and that others may be uncomfortable when they show such material in public. People do make mistakes, but if someone made mistakes similar to those originally being discussed in other kinds of conferences, they'd be in trouble; if they made them in a business context, they'd risk being disciplined or fired.
It's quite possible that ignoring differences in attitudes promotes a culture where people believe that everyone else has the same view as they do. This is where a community risks becoming some kind of clique, and with that the danger that people's behaviour becomes exclusionary. This isn't about whether people should or should not feel entitled to be offended according to what you, I or a number of other commentators believe to be offensive or inoffensive - it's about whether people actually were offended (reportedly the case), whether the presenter anticipated it, and whether the presenter was acting according to the norms of the community.
If normal (or perceived to be normal) community behaviour involves offending people, then examining the effects on the community is an obvious line of further inquiry. It may be an oversimplification to say that community behaviour is the only reason for the absence or underrepresentation of a particular group, but that's no reason to disregard it as a source of legitimate concern.
I made that comment about calling the police, and I stand by it. In Minnesota (Not the entire US, it is a state law) it is illegal to show porn in a public setting. If this was a pron conference the police are likely to laugh, but since it wasn't, it was a tech conference.
# Henry Miller
What's basically wrong with PJs position is encapsulated in the following paragraphs :
[quote] See, the difference between me and the people who are talking about how we should fix this "problem", is that they believe that it's possible to reform the attitudes of the uncivilized en masse, and I don't. Instead of trying to reform them, I simply don't hire them in the first place. No amount of technical competence is enough to make up for somebody being an a**hole, and it's not my job to teach somebody how to be a decent human being. I'm running a place of business, not a charm school or etiquette academy.
...
If women aren't applying because they aren't interested in IT, is that really a problem? If they're not applying because they're being discouraged by society in general, well, perhaps that's a problem, but it's not especially actionable on an individual level, so why worry?
[/quote]
In other words, individualistically oriented PJ doesn't believe that problems due to "society in general" can be actioned on an individual level.
But society-wide behaviour is nothing but the sum of all the little actions. To re-use the other quote you posted (I assume, approvingly) "Is living your life in an individually responsible way enough to bring about the kind of change that you would hope for? I think the answer is no. It takes collective action."
We all know that individually driving our cars doesn't hurt the environment. It's only because we all do it, so much of the time, that it becomes a problem. So does that mean this isn't "actionable" individually?
Maybe. And, if so, only concerted political power can have an effect. Maybe not.
What's the difference in the case of women discouraged from certain life-possibilities by society?
An individual joking reference to soft-porn means nothing on it's own, and every man or woman who thinks about it logically knows this. But cumulatively, we live in an atmosphere polluted by certain conceptions of the appropriate and inappropriate roles for women and men. Women are to be soft, caring, emotional, certainly not abstract, rational and detached from their bodies. Women are told by society, via institutions like Playboy, to be thin, pert, sensuous, concerned about their appearance. And we're surprised they don't embrace a culture that celebrates 24 hour hackathons fueled by pizza and Jolt-Cola?
Showing stats from playboy is not "insulting" - which is a meaningless idea, easy to dismiss - but it is another release into the memeosphere of contaminated ideas. Playboy is in the same position as a factory pumping out sulfur-dioxide. It makes it harder for everyone to breath an air free of these stereotypes.
But it's not impossible to "action" this on an individual level. You can do it by a) choosing not to promote, even with sympathetic humour, this kind of stereotyping publication, b) reminding everyone that this kind of publication is problematic and hoping that they agree with you and do the same. That's not "authoritarian" or creating an even more hostile environment.
Eventually, in the very long term, you hope that less of this propaganda => women feel less pressurized to conform to these social norms => women with more freedom to explore the possible space of career opportunities => more women in IT. (Not because more women in IT is necessarily an important goal, but because their absensce is likely to be a symptom of their lack of freedom.)
 Harm is harm. Whether it's "wrong" to harm someone or not is independent of their capacity to absorb your attack. We wouldn't argue that I can rob your house because it's insulting to assume you don't have the economic capability to recover from the loss. Or that racist language shouldn't be discouraged because it's insulting to assume that blacks can't rise above being called "nigger". (Or maybe there are people who argue that second.)
Systematic problems need collective action to resolve. Education may not be sufficient, but it's hard to see how to get started other than by talking and suggesting that it's everyone's "job" or responsibility to try to teach others how to be decent human beings.
PS : Obviously, all causal hypotheses are open to criticism. Maybe Playboy doesn't have any causal effect on the way women see themselves. But I don't see arguments like yours or Eby's being grounded in actual engagement with that debate. They just assume, axiomatically, that there's no case to answer here.
You wrote:
In other words, individualistically oriented PJ doesn't believe that problems due to "society in general" can be actioned on an individual level.That's not quite correct. I'm saying that my individual action isn't going to change everybody else's. That's not the same thing as saying it's not actionable, period. I'm just saying that if I'm already hiring 50% females, there's not a whole lot more I can do to improve the industry at large.
An individual joking reference to soft-porn means nothing on it's own, and every man or woman who thinks about it logically knows this. But cumulatively, we live in an atmosphere polluted by certain conceptions of the appropriate and inappropriate roles for women and men. Women are to be soft, caring, emotional, certainly not abstract, rational and detached from their bodies. Women are told by society, via institutions like Playboy, to be thin, pert, sensuous, concerned about their appearance. And we're surprised they don't embrace a culture that celebrates 24 hour hackathons fueled by pizza and Jolt-Cola?I'm not surprised either, but I don't think women avoid a culture of hackathons because they are watching their weight. Let's be serious -- there are a huge number of societal factors in how a person chooses their profession, and the relation between body image and computer science is not at the top of that list. Is it discriminatory not to offer healthy snacks at user group meetings? Would healthy snacks help bring in more women? This line of thinking is silly.
Body issues are important to women's role in society at large, but it's really not important to this discussion.
Showing stats from playboy is not "insulting" - which is a meaningless idea, easy to dismiss - but it is another release into the memeosphere of contaminated ideas. Playboy is in the same position as a factory pumping out sulfur-dioxide. It makes it harder for everyone to breath an air free of these stereotypes.
[...]
 Harm is harm. Whether it's "wrong" to harm someone or not is independent of their capacity to absorb your attack. We wouldn't argue that I can rob your house because it's insulting to assume you don't have the economic capability to recover from the loss. Or that racist language shouldn't be discouraged because it's insulting to assume that blacks can't rise above being called "nigger". (Or maybe there are people who argue that second.)
Showing a naked woman is not the same as being racist. Again, this is where the argument becomes unreasonable. If someone made misogynist jokes or statements in their presentation, people should walk out, and they should be very angry at the person. Porn is not hate. I would be bothered if someone was racist or misogynistic even if they didn't express their opinion, or if they couched their language in ways to make it seem acceptable. I am not bothered that someone looks at porn. I'm not going to be offended if someone says that they themselves look at porn. You still shouldn't put actual porn up on the screen, but it's a reasonable item of discussion anywhere where the internet or the web is being discussed.
Eventually, in the very long term, you hope that less of this propaganda => women feel less pressurized to conform to these social norms => women with more freedom to explore the possible space of career opportunities => more women in IT. (Not because more women in IT is necessarily an important goal, but because their absensce is likely to be a symptom of their lack of freedom.)It's a different issue, but I don't entirely believe this line of thinking. Women aren't in IT because women choose not to be in IT. That is a choice they make as individuals -- sometimes for bad reasons (e.g. fear or pressure), but often for completely reasonable reasons (they don't want to sit in front of a computer screen for eight hours a day). That women and men make very different choices does not necessarily imply that there is coercion involved. That women on the whole tend not to go into certain professions does not necessarily mean that they are victims of any societal injustice.
# Ian Bicking
[quote]
Showing a naked woman is not the same as being racist. Again, this is where the argument becomes unreasonable. If someone made misogynist jokes or statements in their presentation, people should walk out, and they should be very angry at the person. Porn is not hate. I would be bothered if someone was racist or misogynistic even if they didn't express their opinion, or if they couched their language in ways to make it seem acceptable. I am not bothered that someone looks at porn. I'm not going to be offended if someone says that they themselves look at porn. You still shouldn't put actual porn up on the screen, but it's a reasonable item of discussion anywhere where the internet or the web is being discussed.
[/quote]
Ian, the reason I'm pushing the pollution analogy here is to get away from terminology like "hate" and "insult". Sure, porn is not hate. But it may nevertheless be harmful.
Your assumption seems to be that if there's no malign intention behind something then it's OK. But there's no malign intention behind pumping out sulphur-dioxide into the atmosphere either. It's just a side-effect of a perfectly acceptable intention : wanting to make more widgets. The same can be true of pornography; we just want to stimulate ourselves. But that doesn't mean it doesn't have malign consequences.
- [quote]
- Eventually, in the very long term, you hope that less of this propaganda => women feel less pressurized to conform to these social norms => women with more freedom to explore the possible space of career opportunities => more women in IT. (Not because more women in IT is necessarily an important goal, but because their absensce is likely to be a symptom of their lack of freedom.)
It's a different issue, but I don't entirely believe this line of thinking. Women aren't in IT because women choose not to be in IT. That is a choice they make as individuals -- sometimes for bad reasons (e.g. fear or pressure), but often for completely reasonable reasons (they don't want to sit in front of a computer screen for eight hours a day). That women and men make very different choices does not necessarily imply that there is coercion involved. That women on the whole tend not to go into certain professions does not necessarily mean that they are victims of any societal injustice.
[/quote]
Actually, I'd say this is the core issue. Sure, you don't believe that there's a causal connection between soft-porn in culture and women not wanting to go into IT, or any other constraints on women's freedom to choose a career. I don't know if there is or not. But isn't this the main point worth discussing? Is there or isn't there?
Personally, I think we can hypothesize many causal paths (of which my hackathon is a slightly frivolous, but not entirely absurd example) which can't be dismissed out-of-hand. Even Eby believes, and has written a lot, that the mind is hackable, that we can train ourselves in new patterns of thought and behaviour. If you believe that, it shouldn't be hard to accept that we get a lot of default configuration from watching how other people parse the world within our culture. And that should be enough to make us sceptical of some naive picture of women "making a choice" independent of any external influence. Is this injustice? It depends. I think if the space of options appears larger to men than to women, and that's due to our cultural defaults rather than real insurmountable physical constraints, then, yes, there's a kind of injustice there.
"""Even Eby believes, and has written a lot, that the mind is hackable, that we can train ourselves in new patterns of thought and behaviour."""
That's a major oversimplification. A big part of what I write about is that there's quite a lot of the mind that is not open to direct extension or hacking, that requires "workarounds" at the conscious or extraconscious (e.g. external systems) level.
An example of this is the idea that men looking at porn are "objectifying" women. The notion of "objectifying" presumes that women are seen as persons first, and then treated as objects. However, this is based on an erroneous assumption about the level on which images are processed. Men have hard-wired pleasure responses to certain visual stimuli, so it's erroneous to attribute any sort of intention to men's response to those images. It simply feels good to look, and it doesn't matter what the man thinks. The most a man can do about the response is to berate himself or feel guilty about the fact of pleasure; there is no way to turn that pleasure response off, only to create various forms of other responses that occur after the fact.
Thus, it makes no sense to me to talk about objectification as if there was some intention on the part of men to "treat women as objects", and this produces non-useful assumptions and behaviors on the part of people whose intention is for men to treat women better. It's more useful for men to learn to accept their pleasure responses and let them go, than to have to spend time fighting them or blaming themselves as bad people for having "objectified" a woman by their response to visual stimuli.
This is really only the tip of the iceberg with respect to non-conscious hardwired responses men have towards women. It's not just pleasure that's activated by the image of an attractive woman, studies have shown that greater helpfulness and risk-taking behavior are also enabled, as well as protectiveness to the female in question. These responses are unconscious and involuntary; they do not require the man's awareness or consent, and are unrelated to the man or woman's availability as a sex partner. The testosterone level of men exposed to the pheromones of ovulating women are also automatically elevated for about 30 minutes, which affects behavior on many levels.
Unfortunately, many branches of feminist thought begin with an assumption that all of these behaviors and responses are voluntary. That is, they attribute to men's actions the intentions that a woman would have to have in order to display the same behaviors, and come to erroneous conclusions. It's this kind of thought that leads to the idea that porn is in some way harmful or toxic because it "encourages men to objectify women". But the reality is that men have their own ability to separate impulse and behavior, and porn is neutral with respect to that. Jerks will be jerks, with or without porn. Likewise, gentlemen will be gentlemen. Porn is 100% a red herring that distracts from the real issue, which is helping men learn empathy.
See, it's not that most jerks are malicious (to women or men), it's that they don't know how any other people feel, because they project their own feelings on to everybody else.  A jerk feels arousal in the presence of a woman, and projects that arousal as being shared by the woman, leading to harassment and even rape.
 And today's "sensitivity" training and sexual harassment workshops are piss-poor at actually teaching it to anyone. To be honest, I'm not sure to what extent it can be taught, because to learn it, you'd have to want to.
This is why I treat some basic empathy as being essential for hiring into a team. I don't know if it's teachable even in theory, let alone in practice, so from a business perspective I can't afford to hire people without it.
I think you've been quite unfair in the way you've summarised Richard's post. If you look behind the words a little, or read the HOWTO Encourage Women in Linux document he's linked to, its not about one particular incident, or even porn in general.
Second, I find it a little upsetting that you call Richard's response "patronizing." He apologised once, on behalf of the committee, for allowing a talk that included provocative, openly sexualized and titillating pictures of women, on a six metre screen, in front of 150 people. His apology was concise, and to the point. I would also say, "professional", but he wasn't being paid. Richard did not condemn CPAN, and he did not cast aspersions upon the morals of the presenter. Like you say, porn is inappropriate in such a setting, so is it that's patronizing about an apology from the committee for allowing it? Please get off his back.
And people wonder why it's so hard to find committee members to run OSS conferences. (OK, yes, I know, it's not just because the general public feel free to complain and nitpick, but that's certainly part of it.)
Third - and tangentially - how can you say that we need to be more accepting of one another's sensibilities in one sentence, and, in the very next, write that "Acme::Playmate is not inappropriate in any way", like it was a self evident fact?
Finally, I agree with you that we need to be careful when we declare particular lines of thought and behaviour "bad". However, I don't really see any way around it in this case. Whatever the setting, if men start acting like they're at the pub with their mates, then - more often than not - women are going to feel uncomfortable and leave. I think OSS communities can work toward being more friendly to women without becoming dull and disingenuous, because I've been part of communities that have managed it.
I also agree that more needs to be done than simply avoid giving offense. The HOWTO has some ideas, but I know - from your previous posts - that you've thought a lot about this, and I'd like to hear your ideas.
Thanks, Alan, for getting to this before I did.  Some inappropriate material that offended more than a few people in the audience was shown. At the first available opportunity Richard, acting as Program Chair, apologised on behalf of the conference for the talk.
This was extremely professional of him, not "patronising". If OSS conferences (particularly volunteer-run ones like OSDC, PyCon and YAPC) want to actually be treated seriously, they could do a lot worse than bear this example in mind. You can't plan for all contingencies. You can, however, step up and deal with things when they go pear-shaped.
I'm not going to comment any further on this, although I have considered it - but I'd suggest you actually ask the people who were in the talk (particularly the women) as to whether they were offended. Hint: It wasn't just a couple of booby shots that was the be-all and end-all of the offensive material. Hint 2: The women (and some of the men) I've spoken to were offended, and in some cases, very offended.
"""Claiming that Richard's response was patronising is the worst sort of nonsense"""
For the record, I said that Richard's post was patronising, not his response. However, if his response mentioned women specifically (as opposed to saying the porn was inappropriate), then it was patronising, too, and counterproductive to his goals (for more than one reason).
I find it interesting that all of the people involved in this discussion, now including me, are men. Have any of you any connection to or involvement in the ACM Committee on Women in Computing? http://women.acm.org/.


etg.simulation.simulation module¶
This module contains the simulation and all otherwise related functions.
-
class
etg.simulation.simulation.
Season
(name, start_date, current_date)[source]¶ Bases:
object
This class represents a single season for use within the game.
-
class
etg.simulation.simulation.
Simulation
(options)[source]¶ Bases:
object
The actual simulation for the game.
Parameters: - tick_rate – The number of seconds in a tick.
- refraction_ticks – The number of ticks between the decisions that an agent makes.
- agent_options – The options for the generation of the agents
-
approval_rate
¶ The approval for the party that is currently in power. This is the percantage of voters that would vote for that party.
-
change_government_budget
¶ Difference in the government budget since the last election
-
change_government_income
¶ Difference in the income since the last election
-
change_greenness
¶ Difference in the greenness of the energy consumed since the last election
-
days_until_election
¶ The number of days until the next election.
-
greenness
¶ How green the energy consumed by the population is.
-
one_day
= datetime.timedelta(1)¶
-
one_round
= datetime.timedelta(730)¶
-
total_demand
¶ The grand total of energy consumed by the agents in the simulation
-
total_production
¶ The grand total of the energy production, in kWh


with open(current_file, "rb") as f:
ret = bytearray(f.read())
if discard_source:
self.discarded_files.append(current_file)
return ret
with open(current_file, "rb") as f:
ret = bytearray(f.read())
if discard_source:
os.remove(current_file)
return ret