<commit_before>import { MapType, getMapInfo, IS_AMAP } from '../../../helpers/location'
import getRealPath from 'uni-platform/helpers/get-real-path'

export default {
  props: {
    id: {
      type: [Number, String],
      default: ''
    },
    latitude: {
      type: [Number, String],
      require: true
    },
    longitude: {
      type: [Number, String],
      require: true
    },
    title: {
      type: String,
      default: ''
    },
    iconPath: {
      type: String,
      require: true
    },
    rotate: {
      type: [Number, String],
      default: 0
    },
    alpha: {
      type: [Number, String],
      default: 1
    },
    width: {
      type: [Number, String],
      default: ''
    },
    height: {
      type: [Number, String],
      default: ''
    },
    callout: {
      type: Object,
      default: null
    },
    label: {
      type: Object,
      default: null
    },
    anchor: {
      type: Object,
      default: null
    },
    clusterId: {
      type: [Number, String],
      default: ''
    },
    customCallout: {
      type: Object,
      default: null
    },
    ariaLabel: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      idString: String(isNaN(Number(this.id)) ? '' : this.id)
    }
  },
  mounted () {
    const $parent = this.$parent
    $parent.mapReady(() => {
      this._maps = $parent._maps
      this._map = $parent._map
      this.addMarker(this.$props)
      Object.keys(this.$props).forEach(key => {
        this.$watch(key, () => {
          this.updateMarker(this.$props)
        })
      })
    })
  },
  beforeDestroy () {
    this.removeMarker()
  },
  methods: {
    addMarker (props) {
      const maps = this._maps
      const map = this._map
      const marker = this._marker = new maps.Marker({
        map,
        flat: true,
        autoRotation: false
      })
      this.$parent._markers[this.idString] = marker
      this.updateMarker(props)
      if (IS_AMAP) {
        // 不通过 addListener 方式绑定事件，为了规避高德地图覆盖物点击触发map点击问题
        marker.dom.addEventListener('click', e => {
          this.handleAMapMarkerClick(e, marker)
        })
        marker.dom.addEventListener('touchend', e => {
          this.handleAMapMarkerClick(e, marker)
        })
      } else {
        maps.event.addListener(marker, 'click', (e) => {
          const callout = marker.callout
          if (callout && !callout.alwaysVisible) {
            callout.set('visible', !callout.visible)
            if (callout.visible) {
              const div = callout.div
              const parent = div.parentNode
              parent.removeChild(div)
              parent.appendChild(div)
            }
          }

          const event = e.event || e.domEvent

          if (this.idString) {
            const { latitude, longitude } = this.getMarkerLatitudeLongitude(e)
            this.$parent.$trigger('markertap', event, {
              markerId: Number(this.idString),
              latitude,
              longitude
            })
          }
          event.stopPropagation()
        })
        // 处理 google H5移动端 maker 点击触发 map 点击问题
        maps.event.addListener(marker, 'mousedown', (e) => {
          if (e.domEvent) {
            e.domEvent.stopPropagation()
          }
        })
      }
    },
    updateMarker (option) {
      const map = this._map
      const maps = this._maps
      const marker = this._marker
      const title = option.title
      const position = IS_AMAP ? new maps.LngLat(option.longitude, option.latitude) : new maps.LatLng(option.latitude, option.longitude)
      const img = new Image()
      img.onload = () => {
        const anchor = option.anchor || {}
        let icon
        let w
        let h
        const x = typeof anchor.x === 'number' ? anchor.x : 0.5
        const y = typeof anchor.y === 'number' ? anchor.y : 1
        if (option.iconPath && (option.width || option.height)) {
          w = option.width || (img.width / img.height) * option.height
          h = option.height || (img.height / img.width) * option.width
        } else {
          w = img.width / 2
          h = img.height / 2
        }
        const top = h - (h - y * h)
        if ('MarkerImage' in maps) {
          // 腾讯 & google
          icon = new maps.MarkerImage(
            img.src,
            null,
            null,
            new maps.Point(x * w, y * h),
            new maps.Size(w, h)
          )
        } else if ('Icon' in maps) {
          // 高德
          icon = new maps.Icon({
            image: img.src,
            size: new maps.Size(w, h),
            imageSize: new maps.Size(w, h),
            imageOffset: new maps.Pixel(x * w, y * h)
          })
        } else {
          icon = {
            url: img.src,
            anchor: new maps.Point(x, y),
            size: new maps.Size(w, h)
          }
        }
        marker.setPosition(position)
        marker.setIcon(icon)
        if ('setRotation' in marker) {
          marker.setRotation(option.rotate || 0)
        }
        const labelOpt = option.label || {}
        if ('label' in marker) {
          marker.label.setMap(null)
          delete marker.label
        }
        let label
        if (labelOpt.content) {
          const labelStyle = {
            borderColor: labelOpt.borderColor,
            borderWidth: (Number(labelOpt.borderWidth) || 0) + 'px',
            padding: (Number(labelOpt.padding) || 0) + 'px',
            borderRadius: (Number(labelOpt.borderRadius) || 0) + 'px',
            backgroundColor: labelOpt.bgColor,
            color: labelOpt.color,
            fontSize: (labelOpt.fontSize || 14) + 'px',
            lineHeight: (labelOpt.fontSize || 14) + 'px',
            marginLeft: (Number(labelOpt.anchorX || labelOpt.x) || 0) + 'px',
            marginTop: (Number(labelOpt.anchorY || labelOpt.y) || 0) + 'px'
          }
          if ('Label' in maps) {
            // 腾讯
            label = new maps.Label({
              position,
              map: map,
              clickable: false,
              content: labelOpt.content,
              style: labelStyle
            })
            marker.label = label
          } else if ('setLabel' in marker) {
            if (IS_AMAP) {
              const content =
              `

                ${labelOpt.content}

`
              marker.setLabel({
                content,
                direction: 'bottom-right'
              })
            } else {
              // google
              const className = this.updateMarkerLabelStyle(this.idString, labelStyle)
              marker.setLabel({
                text: labelOpt.content,
                color: labelStyle.color,
                fontSize: labelStyle.fontSize,
                className
              })
            }
          }
        }
        const calloutOpt = option.callout || {}
        let callout = marker.callout
        let calloutStyle
        if (calloutOpt.content || title) {
          const boxShadow = '0px 0px 3px 1px rgba(0,0,0,0.5)'
          calloutStyle = calloutOpt.content
            ? {
              position,
              map,
              top,
              // handle AMap callout offset
              offsetY: -option.height / 2,
              content: calloutOpt.content,
              color: calloutOpt.color,
              fontSize: calloutOpt.fontSize,
              borderRadius: calloutOpt.borderRadius,
              bgColor: calloutOpt.bgColor,
              padding: calloutOpt.padding,
              boxShadow: calloutOpt.boxShadow || boxShadow,
              display: calloutOpt.display
            }
            : {
              position,
              map,
              top,
              offsetY: -option.height / 2,
              content: title,
              boxShadow: boxShadow
            }
          if (callout) {
            callout.setOption(calloutStyle)
          } else {
            if (IS_AMAP) {
              const callback = ($event, self) => {
                if (self.idString) {
                  self.$parent.$trigger('callouttap', $event, {
                    markerId: Number(self.idString)
                  })
                }
              }
              callout = marker.callout = new maps.Callout(calloutStyle, callback, this)
            } else {
              callout = marker.callout = new maps.Callout(calloutStyle)
              callout.div.onclick = ($event) => {
                if (this.idString) {
                  this.$parent.$trigger('callouttap', $event, {
                    markerId: Number(this.idString)
                  })
                }
                $event.stopPropagation()
                $event.preventDefault()
              }
            }
          }
        } else {
          if (callout) {
            this.removeMarkerCallout(marker.callout)
            delete marker.callout
          }
        }
      }
      if (option.iconPath) {
        img.src = getRealPath(option.iconPath)
      } else {
        console.error('Marker.iconPath is required.')
      }
    },
    handleAMapMarkerClick (e, marker) {
      const callout = marker.callout
      if (callout && !callout.alwaysVisible) {
        callout.visible = !callout.visible
        if (callout.visible) {
          marker.callout.createAMapText()
        } else {
          marker.callout.removeAMapText()
        }
      }
      if (this.idString) {
        this.$parent.$trigger('markertap', e, {
          markerId: Number(this.idString),
          latitude: marker._position.lat,
          longitude: marker._position.lng
        })
      }
      e.stopPropagation()
    },
    updateMarkerLabelStyle (id, style) {
      const className = 'uni-map-marker-label-' + id
      let styleEl = document.getElementById(className)
      if (!styleEl) {
        styleEl = document.createElement('style')
        styleEl.id = className
        document.head.appendChild(styleEl)
        this.$once('hook:destroyed', () => {
          styleEl.remove()
        })
      }
      const newStyle = Object.assign({}, style, {
        position: 'absolute',
        top: '70px',
        borderStyle: 'solid'
      })
      const div = document.createElement('div')
      Object.keys(newStyle).forEach(key => {
        div.style[key] = newStyle[key] || ''
      })
      styleEl.innerText = `.${className}{${div.getAttribute('style')}}`
      return className
    },
    getMarkerLatitudeLongitude (e) {
      const mapInfo = getMapInfo()
      let latitude
      let longitude

      if (IS_AMAP) {
        latitude = e.lnglat.lat
        longitude = e.lnglat.lng
      } else if (mapInfo.type === MapType.QQ) {
        latitude = e.latLng.lat
        longitude = e.latLng.lng
      } else if (mapInfo.type === MapType.GOOGLE) {
        latitude = e.latLng.lat()
        longitude = e.latLng.lng()
      }
      return { latitude, longitude }
    },
    removeMarker () {
      const marker = this._marker
      if (marker) {
        if (marker.label && 'setMap' in marker.label) {
          marker.label.setMap(null)
        }
        if (marker.callout) {
          this.removeMarkerCallout(marker.callout)
        }
        marker.setMap(null)
      }
      delete this.$parent._markers[this.idString]
      this._marker = null
    },
    removeMarkerCallout (callout) {
      if (IS_AMAP) {
        callout.removeAMapText()
      } else {
        callout.setMap(null)
      }
    }
  },
  render () {
    return null
  }
}
<commit_msg>fix(h5 map): 修复谷歌地图移动端callouttap触发map click<commit_after>import { MapType, getMapInfo, IS_AMAP } from '../../../helpers/location'
import getRealPath from 'uni-platform/helpers/get-real-path'

export default {
  props: {
    id: {
      type: [Number, String],
      default: ''
    },
    latitude: {
      type: [Number, String],
      require: true
    },
    longitude: {
      type: [Number, String],
      require: true
    },
    title: {
      type: String,
      default: ''
    },
    iconPath: {
      type: String,
      require: true
    },
    rotate: {
      type: [Number, String],
      default: 0
    },
    alpha: {
      type: [Number, String],
      default: 1
    },
    width: {
      type: [Number, String],
      default: ''
    },
    height: {
      type: [Number, String],
      default: ''
    },
    callout: {
      type: Object,
      default: null
    },
    label: {
      type: Object,
      default: null
    },
    anchor: {
      type: Object,
      default: null
    },
    clusterId: {
      type: [Number, String],
      default: ''
    },
    customCallout: {
      type: Object,
      default: null
    },
    ariaLabel: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      idString: String(isNaN(Number(this.id)) ? '' : this.id)
    }
  },
  mounted () {
    const $parent = this.$parent
    $parent.mapReady(() => {
      this._maps = $parent._maps
      this._map = $parent._map
      this.addMarker(this.$props)
      Object.keys(this.$props).forEach(key => {
        this.$watch(key, () => {
          this.updateMarker(this.$props)
        })
      })
    })
  },
  beforeDestroy () {
    this.removeMarker()
  },
  methods: {
    addMarker (props) {
      const maps = this._maps
      const map = this._map
      const marker = this._marker = new maps.Marker({
        map,
        flat: true,
        autoRotation: false
      })
      this.$parent._markers[this.idString] = marker
      this.updateMarker(props)
      if (IS_AMAP) {
        // 不通过 addListener 方式绑定事件，为了规避高德地图覆盖物点击触发map点击问题
        marker.dom.addEventListener('click', e => {
          this.handleAMapMarkerClick(e, marker)
        })
        marker.dom.addEventListener('touchend', e => {
          this.handleAMapMarkerClick(e, marker)
        })
      } else {
        maps.event.addListener(marker, 'click', (e) => {
          const callout = marker.callout
          if (callout && !callout.alwaysVisible) {
            callout.set('visible', !callout.visible)
            if (callout.visible) {
              const div = callout.div
              const parent = div.parentNode
              parent.removeChild(div)
              parent.appendChild(div)
            }
          }

          const event = e.event || e.domEvent

          if (this.idString) {
            const { latitude, longitude } = this.getMarkerLatitudeLongitude(e)
            this.$parent.$trigger('markertap', event, {
              markerId: Number(this.idString),
              latitude,
              longitude
            })
          }
          event.stopPropagation()
        })
        // 处理 google H5移动端 maker 点击触发 map 点击问题
        maps.event.addListener(marker, 'mousedown', (e) => {
          if (e.domEvent) {
            e.domEvent.stopPropagation()
          }
        })
      }
    },
    updateMarker (option) {
      const map = this._map
      const maps = this._maps
      const marker = this._marker
      const title = option.title
      const position = IS_AMAP ? new maps.LngLat(option.longitude, option.latitude) : new maps.LatLng(option.latitude, option.longitude)
      const img = new Image()
      img.onload = () => {
        const anchor = option.anchor || {}
        let icon
        let w
        let h
        const x = typeof anchor.x === 'number' ? anchor.x : 0.5
        const y = typeof anchor.y === 'number' ? anchor.y : 1
        if (option.iconPath && (option.width || option.height)) {
          w = option.width || (img.width / img.height) * option.height
          h = option.height || (img.height / img.width) * option.width
        } else {
          w = img.width / 2
          h = img.height / 2
        }
        const top = h - (h - y * h)
        if ('MarkerImage' in maps) {
          // 腾讯 & google
          icon = new maps.MarkerImage(
            img.src,
            null,
            null,
            new maps.Point(x * w, y * h),
            new maps.Size(w, h)
          )
        } else if ('Icon' in maps) {
          // 高德
          icon = new maps.Icon({
            image: img.src,
            size: new maps.Size(w, h),
            imageSize: new maps.Size(w, h),
            imageOffset: new maps.Pixel(x * w, y * h)
          })
        } else {
          icon = {
            url: img.src,
            anchor: new maps.Point(x, y),
            size: new maps.Size(w, h)
          }
        }
        marker.setPosition(position)
        marker.setIcon(icon)
        if ('setRotation' in marker) {
          marker.setRotation(option.rotate || 0)
        }
        const labelOpt = option.label || {}
        if ('label' in marker) {
          marker.label.setMap(null)
          delete marker.label
        }
        let label
        if (labelOpt.content) {
          const labelStyle = {
            borderColor: labelOpt.borderColor,
            borderWidth: (Number(labelOpt.borderWidth) || 0) + 'px',
            padding: (Number(labelOpt.padding) || 0) + 'px',
            borderRadius: (Number(labelOpt.borderRadius) || 0) + 'px',
            backgroundColor: labelOpt.bgColor,
            color: labelOpt.color,
            fontSize: (labelOpt.fontSize || 14) + 'px',
            lineHeight: (labelOpt.fontSize || 14) + 'px',
            marginLeft: (Number(labelOpt.anchorX || labelOpt.x) || 0) + 'px',
            marginTop: (Number(labelOpt.anchorY || labelOpt.y) || 0) + 'px'
          }
          if ('Label' in maps) {
            // 腾讯
            label = new maps.Label({
              position,
              map: map,
              clickable: false,
              content: labelOpt.content,
              style: labelStyle
            })
            marker.label = label
          } else if ('setLabel' in marker) {
            if (IS_AMAP) {
              const content =
              `

                ${labelOpt.content}

`
              marker.setLabel({
                content,
                direction: 'bottom-right'
              })
            } else {
              // google
              const className = this.updateMarkerLabelStyle(this.idString, labelStyle)
              marker.setLabel({
                text: labelOpt.content,
                color: labelStyle.color,
                fontSize: labelStyle.fontSize,
                className
              })
            }
          }
        }
        const calloutOpt = option.callout || {}
        let callout = marker.callout
        let calloutStyle
        if (calloutOpt.content || title) {
          const boxShadow = '0px 0px 3px 1px rgba(0,0,0,0.5)'
          calloutStyle = calloutOpt.content
            ? {
              position,
              map,
              top,
              // handle AMap callout offset
              offsetY: -option.height / 2,
              content: calloutOpt.content,
              color: calloutOpt.color,
              fontSize: calloutOpt.fontSize,
              borderRadius: calloutOpt.borderRadius,
              bgColor: calloutOpt.bgColor,
              padding: calloutOpt.padding,
              boxShadow: calloutOpt.boxShadow || boxShadow,
              display: calloutOpt.display
            }
            : {
              position,
              map,
              top,
              offsetY: -option.height / 2,
              content: title,
              boxShadow: boxShadow
            }
          if (callout) {
            callout.setOption(calloutStyle)
          } else {
            if (IS_AMAP) {
              const callback = ($event, self) => {
                if (self.idString) {
                  self.$parent.$trigger('callouttap', $event, {
                    markerId: Number(self.idString)
                  })
                }
              }
              callout = marker.callout = new maps.Callout(calloutStyle, callback, this)
            } else {
              callout = marker.callout = new maps.Callout(calloutStyle)
              callout.div.onclick = ($event) => {
                if (this.idString) {
                  this.$parent.$trigger('callouttap', $event, {
                    markerId: Number(this.idString)
                  })
                }
                $event.stopPropagation()
                $event.preventDefault()
              }
              // The mobile terminal prevent google map callout click trigger map click
              if (getMapInfo().type === MapType.GOOGLE) {
                callout.div.onpointerdown = (e) => { e.stopPropagation() }
                callout.div.ontouchstart = (e) => { e.stopPropagation() }
              }
            }
          }
        } else {
          if (callout) {
            this.removeMarkerCallout(marker.callout)
            delete marker.callout
          }
        }
      }
      if (option.iconPath) {
        img.src = getRealPath(option.iconPath)
      } else {
        console.error('Marker.iconPath is required.')
      }
    },
    handleAMapMarkerClick (e, marker) {
      const callout = marker.callout
      if (callout && !callout.alwaysVisible) {
        callout.visible = !callout.visible
        if (callout.visible) {
          marker.callout.createAMapText()
        } else {
          marker.callout.removeAMapText()
        }
      }
      if (this.idString) {
        this.$parent.$trigger('markertap', e, {
          markerId: Number(this.idString),
          latitude: marker._position.lat,
          longitude: marker._position.lng
        })
      }
      e.stopPropagation()
    },
    updateMarkerLabelStyle (id, style) {
      const className = 'uni-map-marker-label-' + id
      let styleEl = document.getElementById(className)
      if (!styleEl) {
        styleEl = document.createElement('style')
        styleEl.id = className
        document.head.appendChild(styleEl)
        this.$once('hook:destroyed', () => {
          styleEl.remove()
        })
      }
      const newStyle = Object.assign({}, style, {
        position: 'absolute',
        top: '70px',
        borderStyle: 'solid'
      })
      const div = document.createElement('div')
      Object.keys(newStyle).forEach(key => {
        div.style[key] = newStyle[key] || ''
      })
      styleEl.innerText = `.${className}{${div.getAttribute('style')}}`
      return className
    },
    getMarkerLatitudeLongitude (e) {
      const mapInfo = getMapInfo()
      let latitude
      let longitude

      if (IS_AMAP) {
        latitude = e.lnglat.lat
        longitude = e.lnglat.lng
      } else if (mapInfo.type === MapType.QQ) {
        latitude = e.latLng.lat
        longitude = e.latLng.lng
      } else if (mapInfo.type === MapType.GOOGLE) {
        latitude = e.latLng.lat()
        longitude = e.latLng.lng()
      }
      return { latitude, longitude }
    },
    removeMarker () {
      const marker = this._marker
      if (marker) {
        if (marker.label && 'setMap' in marker.label) {
          marker.label.setMap(null)
        }
        if (marker.callout) {
          this.removeMarkerCallout(marker.callout)
        }
        marker.setMap(null)
      }
      delete this.$parent._markers[this.idString]
      this._marker = null
    },
    removeMarkerCallout (callout) {
      if (IS_AMAP) {
        callout.removeAMapText()
      } else {
        callout.setMap(null)
      }
    }
  },
  render () {
    return null
  }
}
<|endoftext|>


<commit_before>
module.exports = function (grunt) {
    'use strict';

    grunt.registerTask(
        'build-docs',
        'Doc building entry point',
        function () {
            grunt.task.run('sass:docs');
            grunt.task.run('symlink:core');

            if (grunt.config('pkg').name !== 'asimov-core') {
                grunt.task.run('symlink:docs');
            }

            grunt.task.run('sync:docs');
            grunt.task.run('template:docs');
            grunt.task.run('exec:docs');
        }
    );
};
<commit_msg>fix(build): fix grunt bug with generating docs<commit_after>
module.exports = function (grunt) {
    'use strict';

    grunt.registerTask(
        'build-docs',
        'Doc building entry point',
        function () {
            grunt.task.run('sass:docs');
            grunt.task.run('symlink:core');

            if (grunt.config('bower').name !== 'asimov-core') {
                grunt.task.run('symlink:docs');
            }

            grunt.task.run('sync:docs');
            grunt.task.run('template:docs');
            grunt.task.run('exec:docs');
        }
    );
};
<|endoftext|>


<commit_before>dojo.provide("dijit._editor.plugins.TextColor");

dojo.require("dijit._editor._Plugin");
dojo.require("dijit.ColorPalette");

dojo.declare("dijit._editor.plugins.TextColor", dijit._editor._Plugin, {
	// summary:
	//		This plugin provides dropdown color pickers for setting text color and background color
	//
	// description:
	//		The commands provided by this plugin are:
	//		* foreColor - sets the text color
	//		* hiliteColor - sets the background color

	// Override _Plugin.buttonClass to use DropDownButton (with ColorPalette) to control this plugin
	buttonClass: dijit.form.DropDownButton,

	//TODO: set initial focus/selection state?

	constructor: function(){
		this.dropDown = new dijit.ColorPalette();
		this.connect(this.dropDown, "onChange", function(color){
			this.editor.execCommand(this.command, color);

		});
	},

	updateState: function(){
		// summary:
		//		Overrides _Plugin.updateState().  This updates the ColorPalette
		//		to show the color of the currently selected text.
		// tags:
		//		protected

		var _e = this.editor;
		var _c = this.command;
		if(!_e || !_e.isLoaded || !_c.length){
			return;
		}

		if(this.button){
			var value;
			try{
				value = _e.queryCommandValue(_c)|| "";
			}catch(e){
				//Firefox may throw error above if the editor is just loaded, ignore it
				value = "";
			}
		}

		if(value == ""){
			value = "#000000";
		}
		if(value == "transparent"){
			value = "#ffffff";
		}

		if(typeof value == "string"){
			//if RGB value, convert to hex value
			if(value.indexOf("rgb")> -1){
				value = dojo.colorFromRgb(value).toHex();
			}
		}else{	//it's an integer(IE returns an MS access #)
			value =((value & 0x0000ff)<< 16)|(value & 0x00ff00)|((value & 0xff0000)>>> 16);
			value = value.toString(16);
			value = "#000000".slice(0, 7 - value.length)+ value;

		}

		if(value !== this.dropDown.get('value')){
			this.dropDown.set('value', value, false);
		}
	}
});

// Register this plugin.
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin", null, function(o){
	if(o.plugin){
		return;
	}
	switch(o.args.name){
		case "foreColor":
		case "hiliteColor":
			o.plugin = new dijit._editor.plugins.TextColor({
				command: o.args.name
			});
	}
});
<commit_msg>Tweak to TextColor to fast-close issue caused by changeset 21691 refs #11010<commit_after>dojo.provide("dijit._editor.plugins.TextColor");

dojo.require("dijit._editor._Plugin");
dojo.require("dijit.ColorPalette");

dojo.declare("dijit._editor.plugins.TextColor", dijit._editor._Plugin, {
	// summary:
	//		This plugin provides dropdown color pickers for setting text color and background color
	//
	// description:
	//		The commands provided by this plugin are:
	//		* foreColor - sets the text color
	//		* hiliteColor - sets the background color

	// Override _Plugin.buttonClass to use DropDownButton (with ColorPalette) to control this plugin
	buttonClass: dijit.form.DropDownButton,

	constructor: function(){
		this.dropDown = new dijit.ColorPalette();
		this.connect(this.dropDown, "onChange", function(color){
			this.editor.execCommand(this.command, color);

		});
		// We do not want default command/onclick stuff.
		this.useDefaultCommand = false;
	},

	updateState: function(){
		// summary:
		//		Overrides _Plugin.updateState().  This updates the ColorPalette
		//		to show the color of the currently selected text.
		// tags:
		//		protected

		var _e = this.editor;
		var _c = this.command;
		if(!_e || !_e.isLoaded || !_c.length){
			return;
		}

		if(this.button){
			var value;
			try{
				value = _e.queryCommandValue(_c)|| "";
			}catch(e){
				//Firefox may throw error above if the editor is just loaded, ignore it
				value = "";
			}
		}

		if(value == ""){
			value = "#000000";
		}
		if(value == "transparent"){
			value = "#ffffff";
		}

		if(typeof value == "string"){
			//if RGB value, convert to hex value
			if(value.indexOf("rgb")> -1){
				value = dojo.colorFromRgb(value).toHex();
			}
		}else{	//it's an integer(IE returns an MS access #)
			value =((value & 0x0000ff)<< 16)|(value & 0x00ff00)|((value & 0xff0000)>>> 16);
			value = value.toString(16);
			value = "#000000".slice(0, 7 - value.length)+ value;

		}

		if(value !== this.dropDown.get('value')){
			console.log("Boom?");
			this.dropDown.set('value', value, false);
		}
	}
});

// Register this plugin.
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin", null, function(o){
	if(o.plugin){
		return;
	}
	switch(o.args.name){
		case "foreColor":
		case "hiliteColor":
			o.plugin = new dijit._editor.plugins.TextColor({
				command: o.args.name
			});
	}
});
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
const Electron = require ('electron');
const ElectronDefaultApp = process.defaultApp !== undefined; // indicates unpackaged electron app
const Eapp = Electron.app;
const CONFIG = { // entries are substituted by Makefile.mk (works only in file header)
  /*@EBEAST_CONFIG@*/
};
Eapp.commandLine.appendSwitch ('disable-http-cache');

// split command line options and return one at a time
function pop_arg (args) {
  if (!args.length)
    return undefined;
  let a = args.shift();
  if (args.__nonoption__) {		// yield saved option argument
    args.__nonoption__--;
    return a;
  }
  if (args.skip_defaultapp) {		// finding defaultApp has precedence
    if (/^[^-]/.test (a)) {
      args.skip_defaultapp = false;	// consume process.defaultApp
      return pop_arg (args);
    }
  }
  if (args.seen_separator)		// yield only non-options after '--'
    return a;
  if (/^-[^-]+/.test (a)) {		// pop single letter option
    const rest = a.slice (2);
    if (/^=/.test (rest)) {		// save single letter option argument
      args.unshift (rest.slice (1));
      args.__nonoption__ = 1;
    } else if (rest)
      args.unshift ('-' + rest);	// save adjunct single letter options
    return '-' + a[1];
  } else if (/^--[^-]+/.test (a)) {	// pop long option
    const eq = a.indexOf ('=');
    if (eq > 0) {
      args.unshift (a.slice (eq + 1));	// save long option argument
      args.__nonoption__ = 1;
      return a.slice (0, eq);
    }
    return a;
  } else if (/^--$/.test (a)) {		// stop option parsing
    args.seen_separator = true;
    return pop_arg (args);
  }
  return a;
}

function print_help () {
  const lines = [
    `Usage: ${Eapp.getName()} [OPTIONS] [projectfiles...]`,
    `Options:`,
    `--help        Print command line option help`,
    `--version     Print version information`,
  ];
  console.log (lines.join ('\n'));
}

// parse command line arguments
const project_files = [];
(function () {
  let args = process.argv.slice (1);
  args.skip_defaultapp = ElectronDefaultApp;
  while (args.length) {
    const arg = pop_arg (args);
    if (args.seen_separator) {
      project_files.push (arg);
      continue;
    }
    switch (arg) {
    case '--help':
      print_help();
      Eapp.exit (0);
      break;
    case '--version':
      console.log (Eapp.getName() + ' ' + Eapp.getVersion());
      Eapp.exit (0);
      break;
    default:
      if (/^-/.test (arg)) {
	console.log ('Unknown option: ' + arg);
	print_help();
	Eapp.exit (129);
      }
      project_files.push (arg);
      break;
    }
  }
}) ();

// create the main ebeast window
var win;
function create_window ()
{
  const FS = require ('fs');
  // avoid menu flicker, leave menu construction to the window
  Electron.Menu.setApplicationMenu (null);
  // find some CSS presets needed as BrowserWindow defaults
  let appcss = FS.readFileSync (__dirname + '/assets/stylesheets.css', 'UTF-8');
  let rex = /\bBrowserWindowDefaults\s*{([^}]*)}/m;
  appcss = rex.exec (appcss)[1];       // extract BrowserWindowDefaults section
  rex = /\/\*([^*]|\*[^\/])*\*\//;
  appcss = appcss.replace (rex, ' ');  // remove comments
  rex = /\bbackgroundColor\s*:\s*([^;}]*)\s*[;}]/mi;
  const backgroundColor = rex.exec (appcss)[1];
  rex = /\bdefaultFontSize\s*:\s*([^;}]*)\s*[;}]/mi;
  const defaultFontSize = rex.exec (appcss)[1];
  rex = /\bdefaultMonospaceFontSize\s*:\s*([^;}]*)\s*[;}]/mi;
  const defaultMonospaceFontSize = rex.exec (appcss)[1];
  // window configuraiton
  const options = {
    width: 				1820, // calling win.maximize() causes flicker
    height: 				1365, // using a big initial size avoids flickering
    backgroundColor: 			backgroundColor,
    autoHideMenuBar:			false,
    webPreferences: {
      nodeIntegration:			true,
      devTools:				CONFIG.debug,
      defaultEncoding:			'UTF-8',
      defaultFontSize:			parseInt (defaultFontSize),
      defaultMonospaceFontSize:		parseInt (defaultMonospaceFontSize),
      defaultFontFamily: {
	standard:	'sans',		// 'Times New Roman',
	serif:		'Constantia',	// 'Times New Roman',
	sansSerif:	'Candara',	// 'Arial',
	monospace:	'Consolas',	// 'Courier New',
	cursive:	'Script',	// 'Script',
	fantasy:	'Impact',	// 'Impact',
      },
    },
    show: false, // avoid incremental load effect, see 'ready-to-show'
    darkTheme: true,
  };
  win = new Electron.BrowserWindow (options);
  win.on ('closed', () => { win = null; });
  win.webContents.on ('crashed', function () { Eapp.exit (-128); });
  win.CONFIG = CONFIG;
  win.CONFIG.args = project_files;
  win.once ('ready-to-show', () => { win.show(); });
  win.loadURL ('http://localhost:27239/app.html');
}
Eapp.on ('ready', create_window); // create window once everything is loaded

// quit when all windows are closed.
Eapp.on ('window-all-closed', Eapp.quit);
<commit_msg>EBEAST: main.js: spawn BeastSoundEngine --embed and add clean shutdown<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html

// Build time configuration, substituted in Javascript file headers by Makefile.mk
const CONFIG = {
  /*@EBEAST_CONFIG@*/
};
let win;
let bse_proc; // assigned spawn.child
let verbose = false;

// Load Electron module for BrowserWindow, etc
const Electron = require ('electron');
const ElectronDefaultApp = process.defaultApp !== undefined; // indicates unpackaged electron app
const Eapp = Electron.app;
// Avoid stale sources and storing non-network resources in users home
Eapp.commandLine.appendSwitch ('disable-http-cache');

// create the main ebeast window
function create_window ()
{
  const FS = require ('fs');
  // avoid menu flicker, leave menu construction to the window
  Electron.Menu.setApplicationMenu (null);
  // find some CSS presets needed as BrowserWindow defaults
  let appcss = FS.readFileSync (__dirname + '/assets/stylesheets.css', 'UTF-8');
  let rex = /\bBrowserWindowDefaults\s*{([^}]*)}/m;
  appcss = rex.exec (appcss)[1];       // extract BrowserWindowDefaults section
  rex = /\/\*([^*]|\*[^\/])*\*\//;
  appcss = appcss.replace (rex, ' ');  // remove comments
  rex = /\bbackgroundColor\s*:\s*([^;}]*)\s*[;}]/mi;
  const backgroundColor = rex.exec (appcss)[1];
  rex = /\bdefaultFontSize\s*:\s*([^;}]*)\s*[;}]/mi;
  const defaultFontSize = rex.exec (appcss)[1];
  rex = /\bdefaultMonospaceFontSize\s*:\s*([^;}]*)\s*[;}]/mi;
  const defaultMonospaceFontSize = rex.exec (appcss)[1];
  // window configuraiton
  const options = {
    width: 				1820, // calling win.maximize() causes flicker
    height: 				1365, // using a big initial size avoids flickering
    backgroundColor: 			backgroundColor,
    autoHideMenuBar:			false,
    webPreferences: {
      nodeIntegration:			true,
      devTools:				CONFIG.debug,
      defaultEncoding:			'UTF-8',
      defaultFontSize:			parseInt (defaultFontSize),
      defaultMonospaceFontSize:		parseInt (defaultMonospaceFontSize),
      defaultFontFamily: {
	standard:	'sans',		// 'Times New Roman',
	serif:		'Constantia',	// 'Times New Roman',
	sansSerif:	'Candara',	// 'Arial',
	monospace:	'Consolas',	// 'Courier New',
	cursive:	'Script',	// 'Script',
	fantasy:	'Impact',	// 'Impact',
      },
    },
    show: false, // avoid incremental load effect, see 'ready-to-show'
    darkTheme: true,
  };
  let win = new Electron.BrowserWindow (options);
  win.webContents.on ('crashed', function () { Eapp.exit (-128); });
  win.MAINCONFIG = { args: project_files };
  return win;
}

// Start BeastSoundEngine in private mode
function create_beast_sound_engine (datacb, errorcb) {
  const { spawn } = require ('child_process');
  let args = [ '--embed', '3' ];
  if (verbose)
    args.push ('--verbose');
  let bse_proc = spawn (__dirname + '/../lib/BeastSoundEngine', args, { stdio: [ 'pipe', 'inherit', 'inherit', 'pipe' ] });
  bse_proc.stdio[3].once ('data', (bytes) => datacb (bytes.toString()));
  if (errorcb)
    {
      bse_proc.stdio[3].once ('end', () => errorcb());
      bse_proc.stdio[3].once ('error', (err) => errorcb());
    }
  return bse_proc;
}

// split command line options and return one at a time
function pop_arg (args) {
  if (!args.length)
    return undefined;
  let a = args.shift();
  if (args.__nonoption__) {		// yield saved option argument
    args.__nonoption__--;
    return a;
  }
  if (args.skip_defaultapp) {		// finding defaultApp has precedence
    if (/^[^-]/.test (a)) {
      args.skip_defaultapp = false;	// consume process.defaultApp
      return pop_arg (args);
    }
  }
  if (args.seen_separator)		// yield only non-options after '--'
    return a;
  if (/^-[^-]+/.test (a)) {		// pop single letter option
    const rest = a.slice (2);
    if (/^=/.test (rest)) {		// save single letter option argument
      args.unshift (rest.slice (1));
      args.__nonoption__ = 1;
    } else if (rest)
      args.unshift ('-' + rest);	// save adjunct single letter options
    return '-' + a[1];
  } else if (/^--[^-]+/.test (a)) {	// pop long option
    const eq = a.indexOf ('=');
    if (eq > 0) {
      args.unshift (a.slice (eq + 1));	// save long option argument
      args.__nonoption__ = 1;
      return a.slice (0, eq);
    }
    return a;
  } else if (/^--$/.test (a)) {		// stop option parsing
    args.seen_separator = true;
    return pop_arg (args);
  }
  return a;
}

// Print help/usage
function print_help () {
  const lines = [
    `Usage: ${Eapp.getName()} [OPTIONS] [projectfiles...]`,
    `Options:`,
    `--help        Print command line option help`,
    `--version     Print version information`,
  ];
  console.log (lines.join ('\n'));
}

// parse command line arguments
const project_files = [];
{
  let args = process.argv.slice (1);
  args.skip_defaultapp = ElectronDefaultApp;
  while (args.length) {
    const arg = pop_arg (args);
    if (args.seen_separator) {
      project_files.push (arg);
      continue;
    }
    switch (arg) {
      case '--help':
	print_help();
	main_exit (0);
	break;
      case '--version':
	console.log (Eapp.getName() + ' ' + Eapp.getVersion());
	main_exit (0);
	break;
      case '--verbose':
	verbose = true;
	break;
      default:
	if (/^-/.test (arg)) {
	  console.err ('Unknown option: ' + arg);
	  print_help();
	  main_exit (5);
	}
	project_files.push (arg);
	break;
    }
  }
}

// Start BeastSoundEngine and BrowserWindow
async function startup_components() {
  // configure BrowserWindow with BeastSoundEngine embedding info
  win = create_window();
  win.on ('closed', () => win = null);
  let win_ready = new Promise (resolve => win.once ('ready-to-show', () => resolve ()));
  let embedding_info = new Promise (resolve => bse_proc = create_beast_sound_engine (msg => resolve (msg), () => main_exit (3)));
  const auth = JSON.parse (await embedding_info); // yields JSON: { "url": "ws://127.0.0.1:<PORT>", "subprotocol": "<STRING>" }
  if (!auth.url || !auth.subprotocol)
    main_exit (2);
  win.MAINCONFIG.subprotocols = auth.subprotocol;
  win.loadURL (auth.url);
  await win_ready;
  win.show();
}
Eapp.once ('ready', startup_components); // create BeastSoundEngine and BrowserWindow once everything is loaded

// End process and main_exit all dependent processes
function main_exit (exitcode) {
  if (main_exit.shuttingdown)
    return;
  main_exit.shuttingdown = true;
  if (win)
    {
      win.destroy();
      win = null;
    }
  if (bse_proc)
    bse_proc.kill();
  Eapp.exit (exitcode ? exitcode : 0);
}

// Valid exit
Eapp.once ('window-all-closed', () => {
  win = null; // this *may* be emitted before win.closed
  main_exit (0);
});

// Invalid exit conditions
process.on ('uncaughtException', function (err) {
  console.error (process.argv[0] + ": uncaughtException (" + (new Date).toUTCString() + '):');
  console.error (err);
  main_exit (7);
});
<|endoftext|>


<commit_before>var _ = require('underscore');

var GameServer = function () {
  this.activePlayers = 0;
  this.numberOfRobots = 50;
  this.width = 1280;
  this.height = 640;
  this.spriteSize = 64;
  this.robots = [];
  this.players = {};
};

GameServer.prototype.rand  = function(n){ return Math.floor( Math.random() * n ); };
GameServer.prototype.randX = function() {
  var randx = this.rand(this.maxX()) + this.minX();
  var xoffset = randx % this.spriteSize;
  randx -= xoffset;
  return randx;
};
GameServer.prototype.randY = function() {
  var randy = this.rand(this.maxY()) + this.minY();
  var yoffset = randy % this.spriteSize;
  randy -= yoffset;
  return randy;
};
GameServer.prototype.randDirection = function() {
  var direction = this.rand(5);
  var result;
  if (direction === 0) {
    result = 'Pause';
  } else if (direction === 1) {
    result = 'North';
  } else if (direction === 2) {
    result = 'East';
  } else if (direction === 3) {
    result = 'South';
  } else {
    result = 'West';
  }
  return result;
};
GameServer.prototype.minX = function() { return 0; };
GameServer.prototype.maxX = function() { return this.width - this.spriteSize; };
GameServer.prototype.minY = function() { return 0; };
GameServer.prototype.maxY = function() { return this.height - this.spriteSize; };

GameServer.prototype.initalize = function() {
  this.initRobots();
  setInterval(this.moveRobots.bind(this), 1000);
};

GameServer.prototype.initRobots = function() {
  var direction = this.randDirection();
  this.robots = _.map(_.range(this.numberOfRobots), function(value){
    return {
      id: value,
      x: this.randX(),
      y: this.randY(),
      direction: direction
    };
  }.bind(this));
};

GameServer.prototype.moveRobots = function() {
  _.each(this.robots, function(robot, index, robots) {
    robots[index] = this.moveRobot(robot);
  }.bind(this));
  io.emit('robotMoves', this.robots);
};

GameServer.prototype.moveRobot = function(robot) {
  this.setRobotDirection(robot);
  if (robot.direction === 'North') {
    if (robot.y - this.spriteSize < this.minY()) {
      this.moveRobot(robot);
    } else {
      robot.y -= this.spriteSize;
    }
  } else if (robot.direction === 'South') {
    if (robot.y + this.spriteSize > this.maxY()) {
      this.moveRobot(robot);
    } else {
      robot.y += this.spriteSize;
    }
  } else if (robot.direction === 'West') {
    if (robot.x - this.spriteSize < this.minX()) {
      this.moveRobot(robot);
    } else {
      robot.x -= this.spriteSize;
    }
  } else if (robot.direction === 'East') {
    if (robot.x + this.spriteSize > this.maxX()) {
      this.moveRobot(robot);
    } else {
      robot.x += this.spriteSize;
    }
  }
  return robot;
};

GameServer.prototype.setRobotDirection = function(robot){
  if (this.rand(2) === 1) {
    robot.direction = this.randDirection();
  }
};

GameServer.prototype.addPlayer = function(id) {
  this.players[id] = null;
};

GameServer.prototype.removePlayer = function(id) {
  delete this.players[id];
};

GameServer.prototype.addMove = function (id, move) {
  this.players[id] = move;
};

module.exports = GameServer;
<commit_msg>changed to gametick<commit_after>var _ = require('underscore');

var GameServer = function () {
  this.activePlayers = 0;
  this.numberOfRobots = 50;
  this.width = 1280;
  this.height = 640;
  this.spriteSize = 64;
  this.robots = [];
  this.players = {};
};

GameServer.prototype.rand  = function(n){ return Math.floor( Math.random() * n ); };
GameServer.prototype.randX = function() {
  var randx = this.rand(this.maxX()) + this.minX();
  var xoffset = randx % this.spriteSize;
  randx -= xoffset;
  return randx;
};

GameServer.prototype.randY = function() {
  var randy = this.rand(this.maxY()) + this.minY();
  var yoffset = randy % this.spriteSize;
  randy -= yoffset;
  return randy;
};

GameServer.prototype.randDirection = function() {
  var direction = this.rand(5);
  var result;
  if (direction === 0) {
    result = 'Pause';
  } else if (direction === 1) {
    result = 'North';
  } else if (direction === 2) {
    result = 'East';
  } else if (direction === 3) {
    result = 'South';
  } else {
    result = 'West';
  }
  return result;
};

GameServer.prototype.minX = function() { return 0; };
GameServer.prototype.maxX = function() { return this.width - this.spriteSize; };
GameServer.prototype.minY = function() { return 0; };
GameServer.prototype.maxY = function() { return this.height - this.spriteSize; };

GameServer.prototype.initalize = function() {
  this.initRobots();
  setInterval(this.gameTick.bind(this), 1000);
};

GameServer.prototype.gameTick = function() {
  this.moveRobots();
};

GameServer.prototype.initRobots = function() {
  var direction = this.randDirection();
  this.robots = _.map(_.range(this.numberOfRobots), function(value){
    return {
      id: value,
      x: this.randX(),
      y: this.randY(),
      direction: direction
    };
  }.bind(this));
};

GameServer.prototype.moveRobots = function() {
  _.each(this.robots, function(robot, index, robots) {
    robots[index] = this.moveRobot(robot);
  }.bind(this));
  io.emit('robotMoves', this.robots);
};

GameServer.prototype.moveRobot = function(robot) {
  this.setRobotDirection(robot);
  if (robot.direction === 'North') {
    if (robot.y - this.spriteSize < this.minY()) {
      this.moveRobot(robot);
    } else {
      robot.y -= this.spriteSize;
    }
  } else if (robot.direction === 'South') {
    if (robot.y + this.spriteSize > this.maxY()) {
      this.moveRobot(robot);
    } else {
      robot.y += this.spriteSize;
    }
  } else if (robot.direction === 'West') {
    if (robot.x - this.spriteSize < this.minX()) {
      this.moveRobot(robot);
    } else {
      robot.x -= this.spriteSize;
    }
  } else if (robot.direction === 'East') {
    if (robot.x + this.spriteSize > this.maxX()) {
      this.moveRobot(robot);
    } else {
      robot.x += this.spriteSize;
    }
  }
  return robot;
};

GameServer.prototype.setRobotDirection = function(robot){
  if (this.rand(2) === 1) {
    robot.direction = this.randDirection();
  }
};

GameServer.prototype.addPlayer = function(id) {
  this.players[id] = null;
};

GameServer.prototype.removePlayer = function(id) {
  delete this.players[id];
};

GameServer.prototype.addMove = function (id, move) {
  this.players[id] = move;
};

module.exports = GameServer;
<|endoftext|>


<commit_before>'use strict';

/*global ajax*/
describe('base api function', function () {
	beforeEach(function () {
	});

	it('should have a working test harness', function () {
		expect(true).not.toBe(false);
	});

	it('should exist', function () {
		expect(typeof ajax).toBe('function');
	});

	it('should return nothing', function () {
		var result = ajax('http://mozilla.org', null, function (d, s, x) {
		});
		expect(result).toBeUndefined();
	});
});

describe('makes async requests', function () {
	iit('should return something', function (done) {
		ajax('https://developer.mozilla.org/search.json?q=cats', null, function (result, status, xhr) {
			expect(result).not.toBeUndefined();
			expect(xhr.startedAt).not.toBeUndefined();
			expect(status).toBe(200);
			done();
		});
	});
});<commit_msg>fix it, yo<commit_after>'use strict';

/*global ajax*/
describe('base api function', function () {
	it('should have a working test harness', function () {
		expect(true).not.toBe(false);
	});

	it('should exist', function () {
		expect(typeof ajax).toBe('function');
	});

	it('should return nothing', function () {
		var result = ajax('http://mozilla.org', null, function (d, s, x) {
		});
		expect(result).toBeUndefined();
	});
});

describe('makes async requests', function () {
	it('should return something', function (done) {
		ajax('https://developer.mozilla.org/search.json?q=cats', null, function (result, status, xhr) {
			expect(result).not.toBeUndefined();
			expect(xhr.startedAt).not.toBeUndefined();
			expect(status).toBe(200);
			done();
		});
	});
});<|endoftext|>


<commit_before>var clapsound = new Audio('clap.wav');

function clapMeme() {
  var checked = $(".caps").prop('checked');
  var original = $('.meme').val().split('');
  var newMeme = original.map(function(value) {
    if(value === ' '){
      return (' \uD83D\uDC4F ');
    }else{
      return checked ? value.toUpperCase() : value
    }
  });

  newMeme.unshift('\uD83D\uDC4F ');
  newMeme.push('\uD83D\uDC4F');

  document.querySelector('.memeSection').innerText = newMeme.join('');
  copyMeme(newMeme.join(''))
  clapsay(original.join(''));
};

function copyMeme(meme) {
  document.querySelector('.hiddenMeme').value = meme;
  document.querySelector('.hiddenMeme').select();
  document.execCommand("Copy");
}

function clapsay(text) {
  let textArray = text.split(' ');
  textArray.forEach((item) => {
    var msg = new SpeechSynthesisUtterance();
    var voices = window.speechSynthesis.getVoices();
    msg.voice = voices[10]; // Note: some voices don't support altering params
    msg.voiceURI = 'native';
    msg.volume = 1; // 0 to 1
    msg.rate = 1; // 0.1 to 10
    msg.pitch = 1; //0 to 2
    msg.text = item;
    msg.lang = 'en-US';

    msg.onend = function(event) {
      console.log('Finished in ' + event.elapsedTime + ' seconds.');
    };

    msg.onend = function(event) {
      clapsound.play();
    }
    msg.onstart = function(event) {
      clapsound.play();
    }
    //clapsound.play();
    speechSynthesis.speak(msg);
  })
}

$(document).ready(function(){
  document.querySelector('.memeStr').addEventListener('click', clapMeme);
  document.querySelector('.meme').addEventListener('keydown', function(e) {
    if (e.key === "Enter") { clapMeme(); }
  });;
});

<commit_msg>Trim input<commit_after>var clapsound = new Audio('clap.wav');

function clapMeme() {
  var checked = $(".caps").prop('checked');
  var original = $('.meme').trim().val().split('');
  var newMeme = original.map(function(value) {
    if(value === ' '){
      return (' \uD83D\uDC4F ');
    }else{
      return checked ? value.toUpperCase() : value
    }
  });

  newMeme.unshift('\uD83D\uDC4F ');
  newMeme.push('\uD83D\uDC4F');

  document.querySelector('.memeSection').innerText = newMeme.join('');
  copyMeme(newMeme.join(''))
  clapsay(original.join(''));
};

function copyMeme(meme) {
  document.querySelector('.hiddenMeme').value = meme;
  document.querySelector('.hiddenMeme').select();
  document.execCommand("Copy");
}

function clapsay(text) {
  let textArray = text.split(' ');
  textArray.forEach((item) => {
    var msg = new SpeechSynthesisUtterance();
    var voices = window.speechSynthesis.getVoices();
    msg.voice = voices[10]; // Note: some voices don't support altering params
    msg.voiceURI = 'native';
    msg.volume = 1; // 0 to 1
    msg.rate = 1; // 0.1 to 10
    msg.pitch = 1; //0 to 2
    msg.text = item;
    msg.lang = 'en-US';

    msg.onend = function(event) {
      console.log('Finished in ' + event.elapsedTime + ' seconds.');
    };

    msg.onend = function(event) {
      clapsound.play();
    }
    msg.onstart = function(event) {
      clapsound.play();
    }
    //clapsound.play();
    speechSynthesis.speak(msg);
  })
}

$(document).ready(function(){
  document.querySelector('.memeStr').addEventListener('click', clapMeme);
  document.querySelector('.meme').addEventListener('keydown', function(e) {
    if (e.key === "Enter") { clapMeme(); }
  });;
});

<|endoftext|>


<commit_before>describe("Svg to Image", function () {
    "use strict";

    var createElementFrom = function (htmlString) {
        var div = document.createElement('div');
        div.innerHTML = htmlString;
        return div.childNodes[0];
    };

    describe("on SVG rendering", function () {
        beforeEach(function () {
            jasmine.addMatchers(imagediff.jasmine);
        });

        ifNotInWebkitIt("should render the SVG", function (done) {
            var referenceImg = createElementFrom(''),
                twoColorSvg = (
                    '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
                        '<foreignObject x="0" y="0" width="100%" height="100%">' +
                            '' +
                                '' +
                                    '' +
                                '' +
                                '' +
                                    '

' +
                                    '

' +
                                '' +
                            '' +
                        '</foreignObject>' +
                    '</svg>'
                );

            referenceImg.onload = function () {
                svg2image.renderSvg(twoColorSvg, null).then(function (image) {
                    // This fails in Chrome & Safari, possibly due to a bug with same origin policy stuff
                    try {
                        expect(image).toImageDiffEqual(referenceImg);
                    } catch (err) {
                        expect(err.message).toBeNull();
                    }
                }).catch(function (err) {
                    expect(err).toBe(null);
                    fail();
                }).finally(done);
            };
        });

        ifNotInWebkitIt("should render an SVG with inline image", function (done) {
            var referenceImg = createElementFrom(''),
                twoColorSvg = (
                    '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
                        '<foreignObject x="0" y="0" width="100%" height="100%">' +
                            '' +
                                '' +
                                    '' +
                                '' +
                                '' +
                                    '' +
                                '' +
                            '' +
                        '</foreignObject>' +
                    '</svg>'
                );

            referenceImg.onload = function () {
                svg2image.renderSvg(twoColorSvg, null).then(function (image) {
                    // This fails in Safari, possibly due to a bug with same origin policy stuff
                    try {
                        expect(image).toImageDiffEqual(referenceImg);
                    } catch (err) {
                        expect(err).toBeNull();
                    }
                }).catch(function (err) {
                    expect(err).toBe(null);
                    fail();
                }).finally(done);
            };
        });

        it("should return an error when the SVG cannot be rendered", function (done) {
            var OldImage = window.Image,
                imageSpy;

            // We need to mock, as only Chrome & Safari seem to throw errors on a faulty SVG
            spyOn(window, "Image").and.callFake(function () {
                // HACK only spy on the first call
                if (!imageSpy) {
                    imageSpy = {};
                    return imageSpy;
                }
                return new OldImage();
            });

            svg2image.renderSvg("svg", null).then(null, done);
            imageSpy.onerror();
            expect(true).toBe(true); // work around warning from jasmine that no expectation is given
        });

        it("should return an image without event listeners attached", function (done) {
            var anSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"></svg>';

            svg2image.renderSvg(anSvg, null).then(function (image) {
                expect(image.onerror).toBeNull();
                expect(image.onload).toBeNull();
            }).catch(function (err) {
                expect(err).toBe(null);
                fail();
            }).finally(done);
        });
    });
});
<commit_msg>Clean up<commit_after>describe("Svg to Image", function () {
    "use strict";

    var createElementFrom = function (htmlString) {
        var div = document.createElement('div');
        div.innerHTML = htmlString;
        return div.childNodes[0];
    };

    describe("on SVG rendering", function () {
        beforeEach(function () {
            jasmine.addMatchers(imagediff.jasmine);
        });

        ifNotInWebkitIt("should render the SVG", function (done) {
            var referenceImg = createElementFrom(''),
                twoColorSvg = (
                    '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
                        '<foreignObject x="0" y="0" width="100%" height="100%">' +
                            '' +
                                '' +
                                    '' +
                                '' +
                                '' +
                                    '

' +
                                    '

' +
                                '' +
                            '' +
                        '</foreignObject>' +
                    '</svg>'
                );

            referenceImg.onload = function () {
                svg2image.renderSvg(twoColorSvg).then(function (image) {
                    // This fails in Chrome & Safari, possibly due to a bug with same origin policy stuff
                    try {
                        expect(image).toImageDiffEqual(referenceImg);
                    } catch (err) {
                        expect(err.message).toBeNull();
                    }
                }).catch(function (err) {
                    expect(err).toBe(null);
                    fail();
                }).finally(done);
            };
        });

        ifNotInWebkitIt("should render an SVG with inline image", function (done) {
            var referenceImg = createElementFrom(''),
                twoColorSvg = (
                    '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
                        '<foreignObject x="0" y="0" width="100%" height="100%">' +
                            '' +
                                '' +
                                    '' +
                                '' +
                                '' +
                                    '' +
                                '' +
                            '' +
                        '</foreignObject>' +
                    '</svg>'
                );

            referenceImg.onload = function () {
                svg2image.renderSvg(twoColorSvg).then(function (image) {
                    // This fails in Safari, possibly due to a bug with same origin policy stuff
                    try {
                        expect(image).toImageDiffEqual(referenceImg);
                    } catch (err) {
                        expect(err).toBeNull();
                    }
                }).catch(function (err) {
                    expect(err).toBe(null);
                    fail();
                }).finally(done);
            };
        });

        it("should return an error when the SVG cannot be rendered", function (done) {
            var OldImage = window.Image,
                imageSpy;

            // We need to mock, as only Chrome & Safari seem to throw errors on a faulty SVG
            spyOn(window, "Image").and.callFake(function () {
                // HACK only spy on the first call
                if (!imageSpy) {
                    imageSpy = {};
                    return imageSpy;
                }
                return new OldImage();
            });

            svg2image.renderSvg("svg").then(null, done);
            imageSpy.onerror();
            expect(true).toBe(true); // work around warning from jasmine that no expectation is given
        });

        it("should return an image without event listeners attached", function (done) {
            var anSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"></svg>';

            svg2image.renderSvg(anSvg).then(function (image) {
                expect(image.onerror).toBeNull();
                expect(image.onload).toBeNull();
            }).catch(function (err) {
                expect(err).toBe(null);
                fail();
            }).finally(done);
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const fs = require('fs');
const http = require('http');

const env = require('../modules/environment');

describe('application', function() {
  this.timeout(10000);

  const serverPort = 8181;
  const testURL = `http://localhost:${serverPort}`

  const config = {
    version: 1,
    teams: [{
      name: 'example_1',
      url: testURL
    }, {
      name: 'example_2',
      url: testURL
    }]
  };

  before(function() {
    this.server = http.createServer(function(req, res) {
      res.writeHead(200, {
        'Content-Type': 'text/html'
      });
      res.end(fs.readFileSync(path.resolve(env.sourceRootDir, 'test/modules/test.html'), 'utf-8'));
    }).listen(serverPort, '127.0.0.1');
  });

  beforeEach(function() {
    fs.writeFileSync(env.configFilePath, JSON.stringify(config));
    this.app = env.getSpectronApp();
    return this.app.start();
  });

  afterEach(function() {
    if (this.app && this.app.isRunning()) {
      return this.app.stop()
    }
  });

  after(function(done) {
    this.server.close(done);
  })

  it('should NOT be able to call Node.js API in webview', function() {
    env.addClientCommands(this.app.client);
    return this.app.client
      .getAttribute('webview', 'nodeintegration').then((nodeintegration) => {
        // nodeintegration is an array of string
        nodeintegration.forEach((n) => {
          n.should.equal('false');
        });
      })
      // webview is handled as a window by chromedriver.
      .windowByIndex(1).isNodeEnabled().should.eventually.be.false
      .windowByIndex(2).isNodeEnabled().should.eventually.be.false;
  });

  it('should NOT be able to call Node.js API in a new window', function() {
    env.addClientCommands(this.app.client);
    return this.app.client
      .execute(function() {
        const webview = document.querySelector('webview');
        webview.executeJavaScript('open_window();');
      })
      .pause(1000) // wait for the new window
      .windowByIndex(3).isNodeEnabled().should.eventually.be.false;
  })
});
<commit_msg>Wait until a new window is opened<commit_after>'use strict';

const path = require('path');
const fs = require('fs');
const http = require('http');

const env = require('../modules/environment');

describe('application', function() {
  this.timeout(10000);

  const serverPort = 8181;
  const testURL = `http://localhost:${serverPort}`

  const config = {
    version: 1,
    teams: [{
      name: 'example_1',
      url: testURL
    }, {
      name: 'example_2',
      url: testURL
    }]
  };

  before(function() {
    this.server = http.createServer(function(req, res) {
      res.writeHead(200, {
        'Content-Type': 'text/html'
      });
      res.end(fs.readFileSync(path.resolve(env.sourceRootDir, 'test/modules/test.html'), 'utf-8'));
    }).listen(serverPort, '127.0.0.1');
  });

  beforeEach(function() {
    fs.writeFileSync(env.configFilePath, JSON.stringify(config));
    this.app = env.getSpectronApp();
    return this.app.start();
  });

  afterEach(function() {
    if (this.app && this.app.isRunning()) {
      return this.app.stop()
    }
  });

  after(function(done) {
    this.server.close(done);
  })

  it('should NOT be able to call Node.js API in webview', function() {
    env.addClientCommands(this.app.client);
    return this.app.client
      .getAttribute('webview', 'nodeintegration').then((nodeintegration) => {
        // nodeintegration is an array of string
        nodeintegration.forEach((n) => {
          n.should.equal('false');
        });
      })
      // webview is handled as a window by chromedriver.
      .windowByIndex(1).isNodeEnabled().should.eventually.be.false
      .windowByIndex(2).isNodeEnabled().should.eventually.be.false;
  });

  it('should NOT be able to call Node.js API in a new window', function() {
    env.addClientCommands(this.app.client);
    const client = this.app.client;
    return this.app.client
      .execute(function() {
        const webview = document.querySelector('webview');
        webview.executeJavaScript('open_window();');
      })
      .waitUntil(function async() {
        return client.windowHandles().then((handles) => {
          return handles.value.length === 4;
        });
      }, 5000, 'expected a new window')
      .windowByIndex(3).isNodeEnabled().should.eventually.be.false;
  })
});
<|endoftext|>


<commit_before>var debug = require("debug")("litesocket");

litesocket = module.exports = function(req, res, next){
	debug("connection opened");
	res.writeHead(200, litesocket.headers(req));
	["sendRetry","sendComment","sendData"].forEach(function(name){
		var fn = litesocket[name];
		res[name] = function(val){
			fn(res, val);
		};
	});
	res.send = function(data, options){
		litesocket.send(res, data, options);
	};

	//send something or the browser gets mad!
	res.send(litesocket.welcome);

	//very important to remove it from the pool and kill off the default 2 minute timeout
	res.socket.setTimeout(0);
	res.socket.emit("agentRemove");

	if(debug.enabled){
		res.on('end', function closed(){
			debug("response closed");
		});
	}

	next();
};
litesocket.handler = function(url, callback){
	this.get(url, litesocket, callback);
};

litesocket.welcome = "You are connected";
litesocket.headers = function(res){
	return {
		"Access-Control-Allow-Origin": "*",
		"Content-Type":"text/event-stream",
		"Cache-Control":"no-cache",
		"Connection":"keep-alive"
	};
}
litesocket.sendId = function(stream, id){
	debug("id: ", id);
	stream.write("id:");
	stream.write(String(id));
	stream.write('\n');
};
litesocket.sendEvent = function(stream, name){
	debug("event:", name);
	stream.write("event:");
	stream.write(String(name));
	stream.write('\n');
};
litesocket.sendRetry = function(stream, ms){
	debug("retry:", ms);
	stream.write("retry:");
	stream.write(String(ms));
	stream.write('\n');
};
litesocket.sendComment = function(stream, comment){
	debug(":", comment);
	stream.write(":");
	stream.write(String(comment).replace(/\n(?=.)/g, '\n:'));
	stream.write('\n');
};
litesocket.sendData = function(stream, data){
	data = String(data).replace(/\n(?=.)/g, '\ndata: ');
	stream.write("data:");
	debug(data);
	stream.write(data);
	if(/\n\r?\n\r?$/.test(data))//the data already has the terminating \n\n at the end
		return;
	stream.write(/\n\r?$/.test(data)? '\n':'\n\n');
};
litesocket.send = function(stream, data, options){
	if(options){
		if(options.comment){
			litesocket.sendComment(stream, options.comment);
		}
		if(options.retry){
			litesocket.sendRetry(stream, options.retry);
		}
		if(options.id){
			litesocket.sendId(stream, options.id);
		}
		if(options.event){
			litesocket.sendEvent(stream, options.event);
		}
	}
	if(data)
		litesocket.sendData(stream, data);
};
<commit_msg>remove chunk encoding<commit_after>var debug = require("debug")("litesocket");

litesocket = module.exports = function(req, res, next){
	debug("connection opened");
	res.useChunkedEncodingByDefault = false;
	res.writeHead(200, litesocket.headers(req));
	["sendRetry","sendComment","sendData"].forEach(function(name){
		var fn = litesocket[name];
		res[name] = function(val){
			fn(res, val);
		};
	});
	res.send = function(data, options){
		litesocket.send(res, data, options);
	};

	//send something or the browser gets mad!
	res.send(litesocket.welcome);

	//very important to remove it from the pool and kill off the default 2 minute timeout
	res.socket.setTimeout(0);
	res.socket.emit("agentRemove");

	if(debug.enabled){
		res.on('end', function closed(){
			debug("response closed");
		});
	}

	next();
};
litesocket.handler = function(url, callback){
	this.get(url, litesocket, callback);
};

litesocket.welcome = "You are connected";
litesocket.headers = function(res){
	return {
		"Access-Control-Allow-Origin": "*",
		"Content-Type":"text/event-stream",
		"Cache-Control":"no-cache"
	};
}
litesocket.sendId = function(stream, id){
	debug("id: ", id);
	stream.write("id:");
	stream.write(String(id));
	stream.write('\n');
};
litesocket.sendEvent = function(stream, name){
	debug("event:", name);
	stream.write("event:");
	stream.write(String(name));
	stream.write('\n');
};
litesocket.sendRetry = function(stream, ms){
	debug("retry:", ms);
	stream.write("retry:");
	stream.write(String(ms));
	stream.write('\n');
};
litesocket.sendComment = function(stream, comment){
	debug(":", comment);
	stream.write(":");
	stream.write(String(comment).replace(/\n(?=.)/g, '\n:'));
	stream.write('\n');
};
litesocket.sendData = function(stream, data){
	data = String(data).replace(/\n(?=.)/g, '\ndata: ');
	stream.write("data:");
	debug(data);
	stream.write(data);
	if(/\n\r?\n\r?$/.test(data))//the data already has the terminating \n\n at the end
		return;
	stream.write(/\n\r?$/.test(data)? '\n':'\n\n');
};
litesocket.send = function(stream, data, options){
	if(options){
		if(options.comment){
			litesocket.sendComment(stream, options.comment);
		}
		if(options.retry){
			litesocket.sendRetry(stream, options.retry);
		}
		if(options.id){
			litesocket.sendId(stream, options.id);
		}
		if(options.event){
			litesocket.sendEvent(stream, options.event);
		}
	}
	if(data)
		litesocket.sendData(stream, data);
};
<|endoftext|>


<commit_before>CT.stream.Video = CT.Class({
	CLASSNAME: "CT.stream.Video",
	_buffers: [],
	_nextChunk: 0,
	_sourceOpen: function() {
		this.log("sourceopen");
		this.setSourceBuffer();
	},
	_sourceUpdate: function() {
		this.log("_sourceUpdate", this._buffers.length,
			this.sourceBuffer.updating, this.mediaSource.readyState);
		if (this.video.error) {
			this.log("ERROR - resetting video");
			this.reset();
		} else if (!this.sourceBuffer.updating) {
			if (this._buffers.length)
				this.sourceBuffer.appendBuffer(this._buffers.shift());
			else if (this.mediaSource.readyState == "open")
				this.mediaSource.endOfStream();
		}
	},
	_error: function(e) {
		this.log("ERROR", e.message, e.target.error);
	},
	setSourceBuffer: function() {
		this.log("setSourceBuffer - exists:", !!this.sourceBuffer);
		if (!this.sourceBuffer) {
			var opts = CT.stream.opts;
			this.sourceBuffer = this.mediaSource.addSourceBuffer(opts.codecs.av);
			this.sourceBuffer.mode = 'sequence';
			this.sourceBuffer.addEventListener("updateend", this._sourceUpdate);
			this.sourceBuffer.addEventListener("error", this._error);
		}
	},
	process: function(dataURL) {
		this.log("process", dataURL.length);
		var that = this, v = this.video;
		CT.stream.util.b64_to_blob(dataURL, function(blob) {
			that.recorder && that.recorder.remember(blob);
			CT.stream.util.blob_to_buffer(blob, function(buffer) {
				that._buffers.push(buffer);
				that._sourceUpdate();
				var target = v.duration - (CT.stream.opts.chunk / 1000);
				if (!v.paused && v.currentTime < target)
					v.currentTime = target;
			});
		});
	},
	start: function() {
		this.log("start (attempting) - paused:", this.video.paused);
		var that = this, prom = this.video.play();
		prom && prom.then(function() {
			that.log("started!!! streaming!");
		})["catch"](function(error) {
			that.log("play failed! awaiting user input (android)", error.message);
			if (CT.stream.opts.requiresInput && !CT.stream.opts.requestedInput) {
				that.audio.node && CT.stream.opts.waiting.push(that.audio.node);
				CT.stream.opts.requestedInput = true;
				(new CT.modal.Prompt({
					cb: CT.stream.opts.startWaiting,
					transition: "fade",
					style: "single-choice",
					data: [ "Play Stream" ],
					prompt: "Ready to stream?"
				})).show();
			}
			CT.stream.opts.waiting.push(that.video);
		});
	},
	_miniRecorder: function() {
		var rec = {
			blobs: [],
			remember: function(blob) {
				if (rec.recording)
					rec.blobs.push(blob);
			},
			start: function() {
				rec.recording = true;
			},
			stop: function() {
				rec.recording = false;
			},
			_save: function(blob_or_blobs) {
				var fname = (new Date()).toString().split("-")[0].replace(/\W/g, "") + ".webm",
					ctf = CT.file.make(blob_or_blobs);
				(new CT.modal.Modal({
					content: [
						CT.dom.div("Your file is ready for download!", "bigger pb10"),
						ctf.download(fname, "click me!", "bold centered block")
					]
				})).show();
			},
			save: function() {
				if (CT.stream.opts.transcoder)
					CT.stream.opts.transcoder(rec._save)(new Blob(rec.blobs));
				else
					rec._save(rec.blobs);
				rec.blobs = [];
			}
		};
		return rec;
	},
	save: function() {
		if (this.recorder) { // stop recording
			this._saveButton.firstChild.classList.remove("buttonActive");
			this.recorder.stop();
			this.recorder.save();
			clearTimeout(this._saveTimer);
			delete this._saveTimer;
			delete this.recorder;
		} else {             // start recording
			this._saveButton.firstChild.classList.add("buttonActive");
			this.recorder = this._miniRecorder();
			this.recorder.start();
			this._saveTimer = setTimeout(this.save, CT.stream.opts.cutoff);
		}
	},
	remove: function() {
		this.video.src = "";
		CT.dom.remove(this.node);
		this.audio.remove();
	},
	_wakeup: function() {
		if (this.video._lastct == this.video.currentTime)
			this.video.currentTime += 1; // help video along....
		this.video._lastct = this.video.currentTime;
	},
	setVideo: function() {
		this.video = this.opts.video || CT.dom.video(this.opts.stream
			&& URL.createObjectURL(this.opts.stream), this.opts.videoClass,
			this.opts.videoId, this.opts.attrs);
		this.video.on("canplay", this.start);
		this.video.on("pause", this.start);
		this.video.on("error", this._error);
	},
	setMediaSource: function() {
		this.mediaSource = new MediaSource();
		this.video.src = URL.createObjectURL(this.mediaSource);
		this.mediaSource.addEventListener("sourceopen", this._sourceOpen);
		this.mediaSource.addEventListener("error", this._error);
	},
	fullscreen: function() {
		var v = this.video;
		if (v.requestFullscreen)
			v.requestFullscreen();
		else if (v.webkitRequestFullscreen)
			v.webkitRequestFullscreen();
	},
	reset: function() {
		var n = Date.now();
		if (this._lastReset && this.opts.onreset &&
			n - this._lastReset < CT.stream.opts.reset)
				this.opts.onreset();
		this._lastReset = n;
		this.video.removeEventListener("canplay", this.start);
		this.video.removeEventListener("pause", this.start);
		this.video.removeEventListener("error", this._error);
		this.setVideo();
		this.video.muted = !this.audio.active;
		this.node.insertBefore(this.video, this.node.video);
		CT.dom.remove(this.node.video);
		this.node.video = this.video;
		this.sourceBuffer.removeEventListener("updateend", this._sourceUpdate);
		this.sourceBuffer.removeEventListener("error", this._error);
		delete this.sourceBuffer;
		this.mediaSource.removeEventListener("sourceopen", this._sourceOpen);
		this.mediaSource.removeEventListener("error", this._error);
		this.setMediaSource();
		this._buffers.shift();
		this.requiredInitChunk = this.receivedInitChunk;
	},
	init: function(opts) {
		this.opts = opts = CT.merge(opts, {
			video: null,
			stream: null,
			className: null,
			id: null,
			frame: true,
			videoClass: null,
			videoId: null,
			watermark: null,
			activeAudio: false,
			onreset: null,
			buttons: [], // only checked when frame is false
			record: { // recorder always shows when frame is true
				streamer: false,
				lurker: false,
				auto: false
			},
			fullscreen: {
				streamer: false,
				lurker: true
			},
			attrs: {
				autoplay: true
			}
		});
		if (opts.stream)
			opts.attrs.mozSrcObject = opts.stream;
		this.setVideo();
		this.audio = new CT.stream.Audio(opts.activeAudio, this);
		this._fullscreenButton = CT.dom.img("/img/fullscreen.png",
			"defpointer hoverglow w80p", this.fullscreen);
		this._saveButton = CT.dom.img("/img/save.png",
			"defpointer hoverglow w80p", this.save);
		this.node = opts.frame ? CT.dom.div([
			this.video,
			CT.dom.div([
				this.audio.button,
				CT.dom.pad(2),
				this._fullscreenButton,
				CT.dom.pad(2),
				this._saveButton
			], "centered")
		], opts.className, opts.id) : CT.dom.div(this.video, opts.className || "fulldef", opts.id);
		this.node.video = this.video;
		var hasRecorder = opts.record[opts.stream ? "streamer" : "lurker"],
			hasFullscreen = opts.fullscreen[opts.stream ? "streamer" : "lurker"];
		if (!opts.frame) {
			var cbl = CT.dom.div(null, "abs cbl");
			if (hasRecorder)
				cbl.appendChild(this._saveButton);
			if (hasFullscreen) {
				if (cbl.childNodes.length)
					cbl.appendChild(CT.dom.pad());
				cbl.appendChild(this._fullscreenButton);
			}
			opts.buttons.forEach(function(b) {
				if (cbl.childNodes.length)
					cbl.appendChild(CT.dom.pad());
				cbl.appendChild(b);
			});
			if (cbl.childNodes.length)
				this.node.appendChild(cbl);
		}
		hasRecorder && opts.record.auto && this.save();
		if (opts.watermark)
			this.node.appendChild(CT.dom.img(opts.watermark, "abs ctr w1-4 mosthigh nofilt"));
		if (opts.stream)
			this.audio.disable();
		else {
			this.setMediaSource();
			this.audio.build();
			setInterval(this._wakeup, 1000);
		}
	}
});<commit_msg>CT.stream.Video.reset(): log timestamp diffs<commit_after>CT.stream.Video = CT.Class({
	CLASSNAME: "CT.stream.Video",
	_buffers: [],
	_nextChunk: 0,
	_sourceOpen: function() {
		this.log("sourceopen");
		this.setSourceBuffer();
	},
	_sourceUpdate: function() {
		this.log("_sourceUpdate", this._buffers.length,
			this.sourceBuffer.updating, this.mediaSource.readyState);
		if (this.video.error) {
			this.log("ERROR - resetting video");
			this.reset();
		} else if (!this.sourceBuffer.updating) {
			if (this._buffers.length)
				this.sourceBuffer.appendBuffer(this._buffers.shift());
			else if (this.mediaSource.readyState == "open")
				this.mediaSource.endOfStream();
		}
	},
	_error: function(e) {
		this.log("ERROR", e.message, e.target.error);
	},
	setSourceBuffer: function() {
		this.log("setSourceBuffer - exists:", !!this.sourceBuffer);
		if (!this.sourceBuffer) {
			var opts = CT.stream.opts;
			this.sourceBuffer = this.mediaSource.addSourceBuffer(opts.codecs.av);
			this.sourceBuffer.mode = 'sequence';
			this.sourceBuffer.addEventListener("updateend", this._sourceUpdate);
			this.sourceBuffer.addEventListener("error", this._error);
		}
	},
	process: function(dataURL) {
		this.log("process", dataURL.length);
		var that = this, v = this.video;
		CT.stream.util.b64_to_blob(dataURL, function(blob) {
			that.recorder && that.recorder.remember(blob);
			CT.stream.util.blob_to_buffer(blob, function(buffer) {
				that._buffers.push(buffer);
				that._sourceUpdate();
				var target = v.duration - (CT.stream.opts.chunk / 1000);
				if (!v.paused && v.currentTime < target)
					v.currentTime = target;
			});
		});
	},
	start: function() {
		this.log("start (attempting) - paused:", this.video.paused);
		var that = this, prom = this.video.play();
		prom && prom.then(function() {
			that.log("started!!! streaming!");
		})["catch"](function(error) {
			that.log("play failed! awaiting user input (android)", error.message);
			if (CT.stream.opts.requiresInput && !CT.stream.opts.requestedInput) {
				that.audio.node && CT.stream.opts.waiting.push(that.audio.node);
				CT.stream.opts.requestedInput = true;
				(new CT.modal.Prompt({
					cb: CT.stream.opts.startWaiting,
					transition: "fade",
					style: "single-choice",
					data: [ "Play Stream" ],
					prompt: "Ready to stream?"
				})).show();
			}
			CT.stream.opts.waiting.push(that.video);
		});
	},
	_miniRecorder: function() {
		var rec = {
			blobs: [],
			remember: function(blob) {
				if (rec.recording)
					rec.blobs.push(blob);
			},
			start: function() {
				rec.recording = true;
			},
			stop: function() {
				rec.recording = false;
			},
			_save: function(blob_or_blobs) {
				var fname = (new Date()).toString().split("-")[0].replace(/\W/g, "") + ".webm",
					ctf = CT.file.make(blob_or_blobs);
				(new CT.modal.Modal({
					content: [
						CT.dom.div("Your file is ready for download!", "bigger pb10"),
						ctf.download(fname, "click me!", "bold centered block")
					]
				})).show();
			},
			save: function() {
				if (CT.stream.opts.transcoder)
					CT.stream.opts.transcoder(rec._save)(new Blob(rec.blobs));
				else
					rec._save(rec.blobs);
				rec.blobs = [];
			}
		};
		return rec;
	},
	save: function() {
		if (this.recorder) { // stop recording
			this._saveButton.firstChild.classList.remove("buttonActive");
			this.recorder.stop();
			this.recorder.save();
			clearTimeout(this._saveTimer);
			delete this._saveTimer;
			delete this.recorder;
		} else {             // start recording
			this._saveButton.firstChild.classList.add("buttonActive");
			this.recorder = this._miniRecorder();
			this.recorder.start();
			this._saveTimer = setTimeout(this.save, CT.stream.opts.cutoff);
		}
	},
	remove: function() {
		this.video.src = "";
		CT.dom.remove(this.node);
		this.audio.remove();
	},
	_wakeup: function() {
		if (this.video._lastct == this.video.currentTime)
			this.video.currentTime += 1; // help video along....
		this.video._lastct = this.video.currentTime;
	},
	setVideo: function() {
		this.video = this.opts.video || CT.dom.video(this.opts.stream
			&& URL.createObjectURL(this.opts.stream), this.opts.videoClass,
			this.opts.videoId, this.opts.attrs);
		this.video.on("canplay", this.start);
		this.video.on("pause", this.start);
		this.video.on("error", this._error);
	},
	setMediaSource: function() {
		this.mediaSource = new MediaSource();
		this.video.src = URL.createObjectURL(this.mediaSource);
		this.mediaSource.addEventListener("sourceopen", this._sourceOpen);
		this.mediaSource.addEventListener("error", this._error);
	},
	fullscreen: function() {
		var v = this.video;
		if (v.requestFullscreen)
			v.requestFullscreen();
		else if (v.webkitRequestFullscreen)
			v.webkitRequestFullscreen();
	},
	reset: function() {
		var n = Date.now();
		if (this._lastReset) {
			var diff = n - this._lastReset;
			this.log("RESET", diff);
			if (this.opts.onreset && diff < CT.stream.opts.reset)
				this.opts.onreset();
		}
		this._lastReset = n;
		this.video.removeEventListener("canplay", this.start);
		this.video.removeEventListener("pause", this.start);
		this.video.removeEventListener("error", this._error);
		this.setVideo();
		this.video.muted = !this.audio.active;
		this.node.insertBefore(this.video, this.node.video);
		CT.dom.remove(this.node.video);
		this.node.video = this.video;
		this.sourceBuffer.removeEventListener("updateend", this._sourceUpdate);
		this.sourceBuffer.removeEventListener("error", this._error);
		delete this.sourceBuffer;
		this.mediaSource.removeEventListener("sourceopen", this._sourceOpen);
		this.mediaSource.removeEventListener("error", this._error);
		this.setMediaSource();
		this._buffers.shift();
		this.requiredInitChunk = this.receivedInitChunk;
	},
	init: function(opts) {
		this.opts = opts = CT.merge(opts, {
			video: null,
			stream: null,
			className: null,
			id: null,
			frame: true,
			videoClass: null,
			videoId: null,
			watermark: null,
			activeAudio: false,
			onreset: null,
			buttons: [], // only checked when frame is false
			record: { // recorder always shows when frame is true
				streamer: false,
				lurker: false,
				auto: false
			},
			fullscreen: {
				streamer: false,
				lurker: true
			},
			attrs: {
				autoplay: true
			}
		});
		if (opts.stream)
			opts.attrs.mozSrcObject = opts.stream;
		this.setVideo();
		this.audio = new CT.stream.Audio(opts.activeAudio, this);
		this._fullscreenButton = CT.dom.img("/img/fullscreen.png",
			"defpointer hoverglow w80p", this.fullscreen);
		this._saveButton = CT.dom.img("/img/save.png",
			"defpointer hoverglow w80p", this.save);
		this.node = opts.frame ? CT.dom.div([
			this.video,
			CT.dom.div([
				this.audio.button,
				CT.dom.pad(2),
				this._fullscreenButton,
				CT.dom.pad(2),
				this._saveButton
			], "centered")
		], opts.className, opts.id) : CT.dom.div(this.video, opts.className || "fulldef", opts.id);
		this.node.video = this.video;
		var hasRecorder = opts.record[opts.stream ? "streamer" : "lurker"],
			hasFullscreen = opts.fullscreen[opts.stream ? "streamer" : "lurker"];
		if (!opts.frame) {
			var cbl = CT.dom.div(null, "abs cbl");
			if (hasRecorder)
				cbl.appendChild(this._saveButton);
			if (hasFullscreen) {
				if (cbl.childNodes.length)
					cbl.appendChild(CT.dom.pad());
				cbl.appendChild(this._fullscreenButton);
			}
			opts.buttons.forEach(function(b) {
				if (cbl.childNodes.length)
					cbl.appendChild(CT.dom.pad());
				cbl.appendChild(b);
			});
			if (cbl.childNodes.length)
				this.node.appendChild(cbl);
		}
		hasRecorder && opts.record.auto && this.save();
		if (opts.watermark)
			this.node.appendChild(CT.dom.img(opts.watermark, "abs ctr w1-4 mosthigh nofilt"));
		if (opts.stream)
			this.audio.disable();
		else {
			this.setMediaSource();
			this.audio.build();
			setInterval(this._wakeup, 1000);
		}
	}
});<|endoftext|>


<commit_before>/**
 * User: simon
 * Date: 30/08/2011
 * Time: 13:52
 * Desc: Loads test specific variables
 */

var assert = require('assert');
var fs = require('fs');
var LZMA  = require('lzma').LZMA;

var lzmaWorker = new LZMA();

var redis = require('redis');
var nock = require('nock');
var log4js = require('log4js');

// set environment specific variables
global.environment  = require(__dirname + '/../../config/environments/test');
global.environment.name = 'test';
process.env.NODE_ENV = 'test';

// don't output logs in test environment to reduce noise
log4js.configure({ appenders: [] });
global.logger = log4js.getLogger();

// Utility function to compress & encode LZMA
function lzma_compress_to_base64(payload, mode, callback) {
  lzmaWorker.compress(payload, mode,
    function(ints) {
      ints = ints.map(function(c) { return String.fromCharCode(c + 128); }).join('');
      var base64 = new Buffer(ints, 'binary').toString('base64');
      callback(null, base64);
    },
    function(/*percent*/) {
      //console.log("Compressing: " + percent + "%");
    }
  );
}

// Check that the response headers do not request caching
// Throws on failure
function checkNoCache(res) {
  assert.ok(!res.headers.hasOwnProperty('x-cache-channel'));
  assert.ok(!res.headers.hasOwnProperty('surrogate-key'));
  assert.ok(!res.headers.hasOwnProperty('cache-control')); // is this correct ?
  assert.ok(!res.headers.hasOwnProperty('last-modified')); // is this correct ?
}

/**
 * Check that the response headers do not request caching
 * @see checkNoCache
 * @param res
 */
function checkCache(res) {
    assert.ok(res.headers.hasOwnProperty('x-cache-channel'));
    assert.ok(res.headers.hasOwnProperty('cache-control'));
    assert.ok(res.headers.hasOwnProperty('last-modified'));
}

function checkSurrogateKey(res, expectedKey) {
    assert.ok(res.headers.hasOwnProperty('surrogate-key'));
    assert.equal(res.headers['surrogate-key'], expectedKey);
}

//global afterEach to capture test suites that leave keys in redis
afterEach(function(done) {

    // restoring nock globally after each suite
    nock.cleanAll();
    nock.enableNetConnect();

    var expectedKeys = {
        'rails:test_windshaft_cartodb_user_1_db:test_table_private_1': true,
        'rails:test_windshaft_cartodb_user_1_db:my_table': true,
        'rails:users:localhost:map_key': true,
        'rails:users:cartodb250user': true,
        'rails:users:localhost': true
    };
    var databasesTasks = { 0: 'users', 5: 'meta'};

    var keysFound = [];
    function taskDone(err, db, keys) {
        if (err) {
            return done(err);
        }

        delete databasesTasks[db];
        keys.forEach(function(k) {
            if (!expectedKeys[k]) {
                keysFound.push('[db='+db+']'+k);
            }
        });

        if (Object.keys(databasesTasks).length === 0) {
            assert.equal(keysFound.length, 0, 'Unexpected keys found in redis: ' + keysFound.join(', '));
            done();
        }
    }

    Object.keys(databasesTasks).forEach(function(db) {
        var redisClient = redis.createClient(global.environment.redis.port);
        redisClient.select(db, function() {
            // Check that we start with an empty redis db
            redisClient.keys("*", function(err, keys) {
                return taskDone(err, db, keys);
            });
        });
    });
});

function deleteRedisKeys(keysToDelete, callback) {

    if (Object.keys(keysToDelete).length === 0) {
        return callback();
    }

    function taskDone(k) {
        delete keysToDelete[k];
        if (Object.keys(keysToDelete).length === 0) {
            callback();
        }
    }

    Object.keys(keysToDelete).forEach(function(k) {
        var redisClient = redis.createClient(global.environment.redis.port);
        redisClient.select(keysToDelete[k], function() {
            redisClient.del(k, function(err, deletedKeysCount) {
                assert.notStrictEqual(deletedKeysCount, 0, 'No KEYS deleted for: [db=' + keysToDelete[k] + ']' + k);
                taskDone(k);
            });
        });
    });
}

function rmdirRecursiveSync(dirname) {
    var files = fs.readdirSync(dirname);
    for (var i=0; i<files.length; ++i) {
        var f = dirname + "/" + files[i];
        var s = fs.lstatSync(f);
        if ( s.isFile() ) {
            fs.unlinkSync(f);
        }
        else {
            rmdirRecursiveSync(f);
        }
    }
}

module.exports = {
  deleteRedisKeys: deleteRedisKeys,
  lzma_compress_to_base64: lzma_compress_to_base64,
  checkNoCache: checkNoCache,
  checkSurrogateKey: checkSurrogateKey,
  checkCache: checkCache,
  rmdirRecursiveSync: rmdirRecursiveSync
};

<commit_msg>Use a set to compare surrogate keys, avoiding key order errors<commit_after>/**
 * User: simon
 * Date: 30/08/2011
 * Time: 13:52
 * Desc: Loads test specific variables
 */

var assert = require('assert');
var fs = require('fs');
var LZMA  = require('lzma').LZMA;

var lzmaWorker = new LZMA();

var redis = require('redis');
var nock = require('nock');
var log4js = require('log4js');

// set environment specific variables
global.environment  = require(__dirname + '/../../config/environments/test');
global.environment.name = 'test';
process.env.NODE_ENV = 'test';

// don't output logs in test environment to reduce noise
log4js.configure({ appenders: [] });
global.logger = log4js.getLogger();

// Utility function to compress & encode LZMA
function lzma_compress_to_base64(payload, mode, callback) {
  lzmaWorker.compress(payload, mode,
    function(ints) {
      ints = ints.map(function(c) { return String.fromCharCode(c + 128); }).join('');
      var base64 = new Buffer(ints, 'binary').toString('base64');
      callback(null, base64);
    },
    function(/*percent*/) {
      //console.log("Compressing: " + percent + "%");
    }
  );
}

// Check that the response headers do not request caching
// Throws on failure
function checkNoCache(res) {
  assert.ok(!res.headers.hasOwnProperty('x-cache-channel'));
  assert.ok(!res.headers.hasOwnProperty('surrogate-key'));
  assert.ok(!res.headers.hasOwnProperty('cache-control')); // is this correct ?
  assert.ok(!res.headers.hasOwnProperty('last-modified')); // is this correct ?
}

/**
 * Check that the response headers do not request caching
 * @see checkNoCache
 * @param res
 */
function checkCache(res) {
    assert.ok(res.headers.hasOwnProperty('x-cache-channel'));
    assert.ok(res.headers.hasOwnProperty('cache-control'));
    assert.ok(res.headers.hasOwnProperty('last-modified'));
}

function checkSurrogateKey(res, expectedKey) {
    assert.ok(res.headers.hasOwnProperty('surrogate-key'));

    function createSet(keys, key) {
        keys[key] = true;
        return keys;
    }
    var keys = res.headers['surrogate-key'].split(' ').reduce(createSet, {});
    var expectedKeys = expectedKey.split(' ').reduce(createSet, {});

    assert.deepEqual(keys, expectedKeys);
}

//global afterEach to capture test suites that leave keys in redis
afterEach(function(done) {

    // restoring nock globally after each suite
    nock.cleanAll();
    nock.enableNetConnect();

    var expectedKeys = {
        'rails:test_windshaft_cartodb_user_1_db:test_table_private_1': true,
        'rails:test_windshaft_cartodb_user_1_db:my_table': true,
        'rails:users:localhost:map_key': true,
        'rails:users:cartodb250user': true,
        'rails:users:localhost': true
    };
    var databasesTasks = { 0: 'users', 5: 'meta'};

    var keysFound = [];
    function taskDone(err, db, keys) {
        if (err) {
            return done(err);
        }

        delete databasesTasks[db];
        keys.forEach(function(k) {
            if (!expectedKeys[k]) {
                keysFound.push('[db='+db+']'+k);
            }
        });

        if (Object.keys(databasesTasks).length === 0) {
            assert.equal(keysFound.length, 0, 'Unexpected keys found in redis: ' + keysFound.join(', '));
            done();
        }
    }

    Object.keys(databasesTasks).forEach(function(db) {
        var redisClient = redis.createClient(global.environment.redis.port);
        redisClient.select(db, function() {
            // Check that we start with an empty redis db
            redisClient.keys("*", function(err, keys) {
                return taskDone(err, db, keys);
            });
        });
    });
});

function deleteRedisKeys(keysToDelete, callback) {

    if (Object.keys(keysToDelete).length === 0) {
        return callback();
    }

    function taskDone(k) {
        delete keysToDelete[k];
        if (Object.keys(keysToDelete).length === 0) {
            callback();
        }
    }

    Object.keys(keysToDelete).forEach(function(k) {
        var redisClient = redis.createClient(global.environment.redis.port);
        redisClient.select(keysToDelete[k], function() {
            redisClient.del(k, function(err, deletedKeysCount) {
                assert.notStrictEqual(deletedKeysCount, 0, 'No KEYS deleted for: [db=' + keysToDelete[k] + ']' + k);
                taskDone(k);
            });
        });
    });
}

function rmdirRecursiveSync(dirname) {
    var files = fs.readdirSync(dirname);
    for (var i=0; i<files.length; ++i) {
        var f = dirname + "/" + files[i];
        var s = fs.lstatSync(f);
        if ( s.isFile() ) {
            fs.unlinkSync(f);
        }
        else {
            rmdirRecursiveSync(f);
        }
    }
}

module.exports = {
  deleteRedisKeys: deleteRedisKeys,
  lzma_compress_to_base64: lzma_compress_to_base64,
  checkNoCache: checkNoCache,
  checkSurrogateKey: checkSurrogateKey,
  checkCache: checkCache,
  rmdirRecursiveSync: rmdirRecursiveSync
};

<|endoftext|>