<commit_before>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/image/Image
@private
*/
define("moxie/runtime/html5/image/Image", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/Exceptions",
	"moxie/core/utils/Encode",
	"moxie/file/Blob",
	"moxie/file/File",
	"moxie/runtime/html5/image/ImageInfo",
	"moxie/runtime/html5/image/ResizerCanvas",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Env"
], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) {

	function HTML5Image() {
		var me = this
		, _img, _imgInfo, _canvas, _binStr, _blob
		, _modified = false // is set true whenever image is modified
		, _preserveHeaders = true
		;

		Basic.extend(this, {
			loadFromBlob: function(blob) {
				var comp = this, I = comp.getRuntime()
				, asBinary = arguments.length > 1 ? arguments[1] : true
				;

				if (!I.can('access_binary')) {
					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
				}

				_blob = blob;

				if (blob.isDetached()) {
					_binStr = blob.getSource();
					_preload.call(this, _binStr);
					return;
				} else {
					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
						if (asBinary) {
							_binStr = _toBinary(dataUrl);
						}
						_preload.call(comp, dataUrl);
					});
				}
			},

			loadFromImage: function(img, exact) {
				this.meta = img.meta;

				_blob = new File(null, {
					name: img.name,
					size: img.size,
					type: img.type
				});

				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
			},

			getInfo: function() {
				var I = this.getRuntime(), info;

				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
					_imgInfo = new ImageInfo(_binStr);
				}

				info = {
					width: _getImg().width || 0,
					height: _getImg().height || 0,
					type: _blob.type || Mime.getFileMime(_blob.name),
					size: _binStr && _binStr.length || _blob.size || 0,
					name: _blob.name || '',
					meta: null
				};

				if (_preserveHeaders) {
					info.meta = _imgInfo && _imgInfo.meta || this.meta || {};

					// store thumbnail data as blob
					if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
						info.meta.thumb.data = new Blob(null, {
							type: 'image/jpeg',
							data: info.meta.thumb.data
						});
					}
				}

				return info;
			},

			resize: function(rect, ratio, options) {
				var canvas = document.createElement('canvas');
				canvas.width = rect.width;
				canvas.height = rect.height;

				canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);

				_canvas = ResizerCanvas.scale(canvas, ratio);

				_preserveHeaders = options.preserveHeaders;

				// rotate if required, according to orientation tag
				if (!_preserveHeaders) {
					var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
					_canvas = _rotateToOrientaion(_canvas, orientation);
				}

				this.width = _canvas.width;
				this.height = _canvas.height;

				_modified = true;

				this.trigger('Resize');
			},

			getAsCanvas: function() {
				if (!_canvas) {
					_canvas = _getCanvas();
				}
				_canvas.id = this.uid + '_canvas';
				return _canvas;
			},

			getAsBlob: function(type, quality) {
				if (type !== this.type) {
					_modified = true; // reconsider the state
					return new File(null, {
						name: _blob.name || '',
						type: type,
						data: me.getAsDataURL(type, quality)
					});
				}
				return new File(null, {
					name: _blob.name || '',
					type: type,
					data: me.getAsBinaryString(type, quality)
				});
			},

			getAsDataURL: function(type) {
				var quality = arguments[1] || 90;

				// if image has not been modified, return the source right away
				if (!_modified) {
					return _img.src;
				}

				// make sure we have a canvas to work with
				_getCanvas();

				if ('image/jpeg' !== type) {
					return _canvas.toDataURL('image/png');
				} else {
					try {
						// older Geckos used to result in an exception on quality argument
						return _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						return _canvas.toDataURL('image/jpeg');
					}
				}
			},

			getAsBinaryString: function(type, quality) {
				// if image has not been modified, return the source right away
				if (!_modified) {
					// if image was not loaded from binary string
					if (!_binStr) {
						_binStr = _toBinary(me.getAsDataURL(type, quality));
					}
					return _binStr;
				}

				if ('image/jpeg' !== type) {
					_binStr = _toBinary(me.getAsDataURL(type, quality));
				} else {
					var dataUrl;

					// if jpeg
					if (!quality) {
						quality = 90;
					}

					// make sure we have a canvas to work with
					_getCanvas();

					try {
						// older Geckos used to result in an exception on quality argument
						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						dataUrl = _canvas.toDataURL('image/jpeg');
					}

					_binStr = _toBinary(dataUrl);

					if (_imgInfo) {
						_binStr = _imgInfo.stripHeaders(_binStr);

						if (_preserveHeaders) {
							// update dimensions info in exif
							if (_imgInfo.meta && _imgInfo.meta.exif) {
								_imgInfo.setExif({
									PixelXDimension: this.width,
									PixelYDimension: this.height
								});
							}

							// re-inject the headers
							_binStr = _imgInfo.writeHeaders(_binStr);
						}

						// will be re-created from fresh on next getInfo call
						_imgInfo.purge();
						_imgInfo = null;
					}
				}

				_modified = false;

				return _binStr;
			},

			destroy: function() {
				me = null;
				_purge.call(this);
				this.getRuntime().getShim().removeInstance(this.uid);
			}
		});

		function _getImg() {
			if (!_canvas && !_img) {
				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
			}
			return _canvas || _img;
		}

		function _getCanvas() {
			var canvas = _getImg();
			if (canvas.nodeName.toLowerCase() == 'canvas') {
				return canvas;
			}
			_canvas = document.createElement('canvas');
			_canvas.width = canvas.width;
			_canvas.height = canvas.height;
			_canvas.getContext("2d").drawImage(canvas, 0, 0);
			return _canvas;
		}

		function _toBinary(str) {
			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
		}

		function _toDataUrl(str, type) {
			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
		}

		function _preload(str) {
			var comp = this;

			_img = new Image();
			_img.onerror = function() {
				_purge.call(this);
				comp.trigger('error', x.ImageError.WRONG_FORMAT);
			};
			_img.onload = function() {
				comp.trigger('load');
			};

			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
		}

		function _readAsDataUrl(file, callback) {
			var comp = this, fr;

			// use FileReader if it's available
			if (window.FileReader) {
				fr = new FileReader();
				fr.onload = function() {
					callback(this.result);
				};
				fr.onerror = function() {
					comp.trigger('error', x.ImageError.WRONG_FORMAT);
				};
				fr.readAsDataURL(file);
			} else {
				return callback(file.getAsDataURL());
			}
		}

		/**
		* Transform canvas coordination according to specified frame size and orientation
		* Orientation value is from EXIF tag
		* @author Shinichi Tomita <shinichi.tomita@gmail.com>
		*/
		function _rotateToOrientaion(img, orientation) {
			var RADIANS = Math.PI/180;
			var canvas = document.createElement('canvas');
			var ctx = canvas.getContext('2d');
			var width = img.width;
			var height = img.height;

			if (Basic.inArray(orientation, [5,6,7,8]) > -1) {
				canvas.width = height;
				canvas.height = width;
			} else {
				canvas.width = width;
				canvas.height = height;
			}

			/**
			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
			*/
			switch (orientation) {
				case 2:
					// horizontal flip
					ctx.translate(width, 0);
					ctx.scale(-1, 1);
					break;
				case 3:
					// 180 rotate left
					ctx.translate(width, height);
					ctx.rotate(180 * RADIANS);
					break;
				case 4:
					// vertical flip
					ctx.translate(0, height);
					ctx.scale(1, -1);
					break;
				case 5:
					// vertical flip + 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.scale(1, -1);
					break;
				case 6:
					// 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.translate(0, -height);
					break;
				case 7:
					// horizontal flip + 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.translate(width, -height);
					ctx.scale(-1, 1);
					break;
				case 8:
					// 90 rotate left
					ctx.rotate(-90 * RADIANS);
					ctx.translate(-width, 0);
					break;
			}

			ctx.drawImage(img, 0, 0, width, height);
			return canvas;
		}

		function _purge() {
			if (_imgInfo) {
				_imgInfo.purge();
				_imgInfo = null;
			}

			// Memory issue for IE/Edge. They Keep a reference to image (because of the onload event) and the object not been collected by GC.
			if (_img) {
				_img.src = '';
			}

			_binStr = _img = _canvas = _blob = null;
			_modified = false;
		}
	}

	return (extensions.Image = HTML5Image);
});
<commit_msg>Image, HTML5: Remove that not working fix for unconfirmed memory leak.<commit_after>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/image/Image
@private
*/
define("moxie/runtime/html5/image/Image", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/Exceptions",
	"moxie/core/utils/Encode",
	"moxie/file/Blob",
	"moxie/file/File",
	"moxie/runtime/html5/image/ImageInfo",
	"moxie/runtime/html5/image/ResizerCanvas",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Env"
], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) {

	function HTML5Image() {
		var me = this
		, _img, _imgInfo, _canvas, _binStr, _blob
		, _modified = false // is set true whenever image is modified
		, _preserveHeaders = true
		;

		Basic.extend(this, {
			loadFromBlob: function(blob) {
				var comp = this, I = comp.getRuntime()
				, asBinary = arguments.length > 1 ? arguments[1] : true
				;

				if (!I.can('access_binary')) {
					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
				}

				_blob = blob;

				if (blob.isDetached()) {
					_binStr = blob.getSource();
					_preload.call(this, _binStr);
					return;
				} else {
					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
						if (asBinary) {
							_binStr = _toBinary(dataUrl);
						}
						_preload.call(comp, dataUrl);
					});
				}
			},

			loadFromImage: function(img, exact) {
				this.meta = img.meta;

				_blob = new File(null, {
					name: img.name,
					size: img.size,
					type: img.type
				});

				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
			},

			getInfo: function() {
				var I = this.getRuntime(), info;

				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
					_imgInfo = new ImageInfo(_binStr);
				}

				info = {
					width: _getImg().width || 0,
					height: _getImg().height || 0,
					type: _blob.type || Mime.getFileMime(_blob.name),
					size: _binStr && _binStr.length || _blob.size || 0,
					name: _blob.name || '',
					meta: null
				};

				if (_preserveHeaders) {
					info.meta = _imgInfo && _imgInfo.meta || this.meta || {};

					// store thumbnail data as blob
					if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
						info.meta.thumb.data = new Blob(null, {
							type: 'image/jpeg',
							data: info.meta.thumb.data
						});
					}
				}

				return info;
			},

			resize: function(rect, ratio, options) {
				var canvas = document.createElement('canvas');
				canvas.width = rect.width;
				canvas.height = rect.height;

				canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);

				_canvas = ResizerCanvas.scale(canvas, ratio);

				_preserveHeaders = options.preserveHeaders;

				// rotate if required, according to orientation tag
				if (!_preserveHeaders) {
					var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
					_canvas = _rotateToOrientaion(_canvas, orientation);
				}

				this.width = _canvas.width;
				this.height = _canvas.height;

				_modified = true;

				this.trigger('Resize');
			},

			getAsCanvas: function() {
				if (!_canvas) {
					_canvas = _getCanvas();
				}
				_canvas.id = this.uid + '_canvas';
				return _canvas;
			},

			getAsBlob: function(type, quality) {
				if (type !== this.type) {
					_modified = true; // reconsider the state
					return new File(null, {
						name: _blob.name || '',
						type: type,
						data: me.getAsDataURL(type, quality)
					});
				}
				return new File(null, {
					name: _blob.name || '',
					type: type,
					data: me.getAsBinaryString(type, quality)
				});
			},

			getAsDataURL: function(type) {
				var quality = arguments[1] || 90;

				// if image has not been modified, return the source right away
				if (!_modified) {
					return _img.src;
				}

				// make sure we have a canvas to work with
				_getCanvas();

				if ('image/jpeg' !== type) {
					return _canvas.toDataURL('image/png');
				} else {
					try {
						// older Geckos used to result in an exception on quality argument
						return _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						return _canvas.toDataURL('image/jpeg');
					}
				}
			},

			getAsBinaryString: function(type, quality) {
				// if image has not been modified, return the source right away
				if (!_modified) {
					// if image was not loaded from binary string
					if (!_binStr) {
						_binStr = _toBinary(me.getAsDataURL(type, quality));
					}
					return _binStr;
				}

				if ('image/jpeg' !== type) {
					_binStr = _toBinary(me.getAsDataURL(type, quality));
				} else {
					var dataUrl;

					// if jpeg
					if (!quality) {
						quality = 90;
					}

					// make sure we have a canvas to work with
					_getCanvas();

					try {
						// older Geckos used to result in an exception on quality argument
						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						dataUrl = _canvas.toDataURL('image/jpeg');
					}

					_binStr = _toBinary(dataUrl);

					if (_imgInfo) {
						_binStr = _imgInfo.stripHeaders(_binStr);

						if (_preserveHeaders) {
							// update dimensions info in exif
							if (_imgInfo.meta && _imgInfo.meta.exif) {
								_imgInfo.setExif({
									PixelXDimension: this.width,
									PixelYDimension: this.height
								});
							}

							// re-inject the headers
							_binStr = _imgInfo.writeHeaders(_binStr);
						}

						// will be re-created from fresh on next getInfo call
						_imgInfo.purge();
						_imgInfo = null;
					}
				}

				_modified = false;

				return _binStr;
			},

			destroy: function() {
				me = null;
				_purge.call(this);
				this.getRuntime().getShim().removeInstance(this.uid);
			}
		});

		function _getImg() {
			if (!_canvas && !_img) {
				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
			}
			return _canvas || _img;
		}

		function _getCanvas() {
			var canvas = _getImg();
			if (canvas.nodeName.toLowerCase() == 'canvas') {
				return canvas;
			}
			_canvas = document.createElement('canvas');
			_canvas.width = canvas.width;
			_canvas.height = canvas.height;
			_canvas.getContext("2d").drawImage(canvas, 0, 0);
			return _canvas;
		}

		function _toBinary(str) {
			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
		}

		function _toDataUrl(str, type) {
			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
		}

		function _preload(str) {
			var comp = this;

			_img = new Image();
			_img.onerror = function() {
				_purge.call(this);
				comp.trigger('error', x.ImageError.WRONG_FORMAT);
			};
			_img.onload = function() {
				comp.trigger('load');
			};

			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
		}

		function _readAsDataUrl(file, callback) {
			var comp = this, fr;

			// use FileReader if it's available
			if (window.FileReader) {
				fr = new FileReader();
				fr.onload = function() {
					callback(this.result);
				};
				fr.onerror = function() {
					comp.trigger('error', x.ImageError.WRONG_FORMAT);
				};
				fr.readAsDataURL(file);
			} else {
				return callback(file.getAsDataURL());
			}
		}

		/**
		* Transform canvas coordination according to specified frame size and orientation
		* Orientation value is from EXIF tag
		* @author Shinichi Tomita <shinichi.tomita@gmail.com>
		*/
		function _rotateToOrientaion(img, orientation) {
			var RADIANS = Math.PI/180;
			var canvas = document.createElement('canvas');
			var ctx = canvas.getContext('2d');
			var width = img.width;
			var height = img.height;

			if (Basic.inArray(orientation, [5,6,7,8]) > -1) {
				canvas.width = height;
				canvas.height = width;
			} else {
				canvas.width = width;
				canvas.height = height;
			}

			/**
			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
			*/
			switch (orientation) {
				case 2:
					// horizontal flip
					ctx.translate(width, 0);
					ctx.scale(-1, 1);
					break;
				case 3:
					// 180 rotate left
					ctx.translate(width, height);
					ctx.rotate(180 * RADIANS);
					break;
				case 4:
					// vertical flip
					ctx.translate(0, height);
					ctx.scale(1, -1);
					break;
				case 5:
					// vertical flip + 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.scale(1, -1);
					break;
				case 6:
					// 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.translate(0, -height);
					break;
				case 7:
					// horizontal flip + 90 rotate right
					ctx.rotate(90 * RADIANS);
					ctx.translate(width, -height);
					ctx.scale(-1, 1);
					break;
				case 8:
					// 90 rotate left
					ctx.rotate(-90 * RADIANS);
					ctx.translate(-width, 0);
					break;
			}

			ctx.drawImage(img, 0, 0, width, height);
			return canvas;
		}

		function _purge() {
			if (_imgInfo) {
				_imgInfo.purge();
				_imgInfo = null;
			}

			_binStr = _img = _canvas = _blob = null;
			_modified = false;
		}
	}

	return (extensions.Image = HTML5Image);
});
<|endoftext|>


<commit_before>import React from 'react';

import { Avatar, Button, Box, Nav, Stack, Text } from 'grommet';

import {
  Analytics,
  Chat,
  Clock,
  Configure,
  Help,
  Projects,
  Split,
  StatusInfoSmall,
} from 'grommet-icons';

import { Sidebar } from '../Sidebar';

const src = '//s.gravatar.com/avatar/b7fb138d53ba0f573212ccce38a7c43b?s=80';

const SidebarHeader = () => (
  <Box align="center" gap="small" direction="row" margin={{ bottom: 'large' }}>
    <Stack alignSelf="start" align="center" anchor="top-right">
      <Avatar src={src} />
      <Box pad="xsmall" background="orange" round responsive={false} />
    </Stack>
    <Text>Shimrit Yacobi</Text>
  </Box>
);

const SidebarButton = ({ icon, label, ...rest }) => (
  <Box pad="small">
    <Button
      gap="medium"
      alignSelf="start"
      plain
      icon={icon}
      label={label}
      {...rest}
    />
  </Box>
);

const SidebarFooter = () => (
  <Nav>
    <SidebarButton icon={<Chat />} />
    <SidebarButton icon={<Help />} />
  </Nav>
);

const MainNavigation = () => (
  <Nav gap="large" responsive={false}>
    <SidebarButton icon={<StatusInfoSmall />} label="Focus" />
    <SidebarButton icon={<Projects />} label="Services" />
    <SidebarButton icon={<Clock />} label="Glances" />
    <SidebarButton icon={<Split />} label="Flows" />
    <SidebarButton icon={<Analytics />} label="Analytics" />
    <SidebarButton icon={<Configure />} label="Configure" />
  </Nav>
);

export const Labels = () => (
  // Uncomment <Grommet> lines when using outside of storybook
  // <Grommet theme={...}>
  <Box direction="row" height={{ min: '100%' }}>
    <Sidebar
      responsive={false}
      background="light-2"
      header={<SidebarHeader />}
      footer={<SidebarFooter />}
      pad={{ left: 'medium', right: 'large', vertical: 'medium' }}
    >
      <MainNavigation />
    </Sidebar>
  </Box>
  // </Grommet>
);

Labels.args = {
  full: true,
};

export default {
  title: 'Layout/Sidebar/Labels',
};
<commit_msg>Fix aria-label violation for Labels story (#6373)<commit_after>import React from 'react';

import { Avatar, Button, Box, Nav, Stack, Text } from 'grommet';

import {
  Analytics,
  Chat,
  Clock,
  Configure,
  Help,
  Projects,
  Split,
  StatusInfoSmall,
} from 'grommet-icons';

import { Sidebar } from '../Sidebar';

const src = '//s.gravatar.com/avatar/b7fb138d53ba0f573212ccce38a7c43b?s=80';

const SidebarHeader = () => (
  <Box align="center" gap="small" direction="row" margin={{ bottom: 'large' }}>
    <Stack alignSelf="start" align="center" anchor="top-right">
      <Avatar src={src} />
      <Box pad="xsmall" background="orange" round responsive={false} />
    </Stack>
    <Text>Shimrit Yacobi</Text>
  </Box>
);

const SidebarButton = ({ icon, label, ...rest }) => (
  <Box pad="small">
    <Button
      gap="medium"
      alignSelf="start"
      plain
      icon={icon}
      label={label}
      {...rest}
    />
  </Box>
);

const SidebarFooter = () => (
  <Nav aria-label="sidebar footer">
    <SidebarButton icon={<Chat />} />
    <SidebarButton icon={<Help />} />
  </Nav>
);

const MainNavigation = () => (
  <Nav aria-label="main navigation" gap="large" responsive={false}>
    <SidebarButton icon={<StatusInfoSmall />} label="Focus" />
    <SidebarButton icon={<Projects />} label="Services" />
    <SidebarButton icon={<Clock />} label="Glances" />
    <SidebarButton icon={<Split />} label="Flows" />
    <SidebarButton icon={<Analytics />} label="Analytics" />
    <SidebarButton icon={<Configure />} label="Configure" />
  </Nav>
);

export const Labels = () => (
  // Uncomment <Grommet> lines when using outside of storybook
  // <Grommet theme={...}>
  <Box direction="row" height={{ min: '100%' }}>
    <Sidebar
      responsive={false}
      background="light-2"
      header={<SidebarHeader />}
      footer={<SidebarFooter />}
      pad={{ left: 'medium', right: 'large', vertical: 'medium' }}
    >
      <MainNavigation />
    </Sidebar>
  </Box>
  // </Grommet>
);

Labels.args = {
  full: true,
};

export default {
  title: 'Layout/Sidebar/Labels',
};
<|endoftext|>


<commit_before>import { Trans } from "@lingui/macro";
import { i18nMark } from "@lingui/react";

import browserInfo from "browser-info";
import classNames from "classnames";
import { Modal } from "reactjs-components";
import PropTypes from "prop-types";
import React from "react";
import { Icon } from "@dcos/ui-kit";
import { SystemIcons } from "@dcos/ui-kit/dist/packages/icons/dist/system-icons-enum";
import { iconSizeXs } from "@dcos/ui-kit/dist/packages/design-tokens/build/js/designTokens";

import ClickToSelect from "../ClickToSelect";
import MetadataStore from "../../stores/MetadataStore";
import ModalHeading from "../modals/ModalHeading";

const METHODS_TO_BIND = ["onClose"];
const osTypes = {
  Windows: "windows",
  "OS X": "darwin",
  Linux: "linux"
};

class CliInstallModal extends React.Component {
  constructor() {
    super(...arguments);

    let selectedOS = browserInfo().os;
    if (!Object.keys(osTypes).includes(selectedOS)) {
      selectedOS = "Linux";
    }

    this.state = { selectedOS };

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  handleSelectedOSChange(selectedOS) {
    this.setState({ selectedOS });
  }

  onClose() {
    this.props.onClose();
  }

  getSubHeader() {
    if (!this.props.subHeaderContent) {
      return false;
    }

    return (

        {this.props.subHeaderContent}

    );
  }

  getCliInstructions() {
    const hostname = global.location.hostname;
    const protocol = global.location.protocol.replace(/[^\w]/g, "");
    let port = "";
    if (global.location.port) {
      port = ":" + global.location.port;
    }
    const clusterUrl = `${protocol}://${hostname}${port}`;
    const { selectedOS } = this.state;

    const downloadUrl = `https://downloads.dcos.io/binaries/cli/${osTypes[selectedOS]}/x86-64/dcos-1.13/dcos`;
    if (selectedOS === "Windows") {
      return this.getWindowsInstallInstruction(clusterUrl, downloadUrl);
    }

    const instructions = [
      `curl ${downloadUrl} -o dcos`,
      `chmod +x ./dcos`,
      `sudo mv dcos /usr/local/bin`,
      `dcos cluster setup ${clusterUrl}`,
      `dcos`
    ].filter(instruction => instruction !== undefined);

    return (

        <Trans render="p" className="short-bottom">
          Copy and paste the code snippet into the terminal:
        </Trans>

          <ClickToSelect>

              {instructions.join(" && \n")}

          </ClickToSelect>

    );
  }

  getWindowsInstallInstruction(clusterUrl, downloadUrl) {
    const steps = [
      `cd path/to/download/directory`,
      `dcos cluster setup ${clusterUrl}`,
      `dcos`
    ]
      .filter(instruction => instruction !== undefined)
      .map((instruction, index) => {
        const helpText =
          index === 0
            ? i18nMark("In Command Prompt, enter")
            : i18nMark("Enter");

        return (

            <Trans render="p" className="short-bottom" id={helpText} />

              <ClickToSelect>

                  {instruction}

              </ClickToSelect>

        );
      });

    return (

        <Trans render="li">
          Download and install:{" "}

            <Icon
              shape={SystemIcons.Download}
              size={iconSizeXs}
              color="currentColor"
            />
            Download dcos.exe

          .
        </Trans>
        {steps}

    );
  }

  getOSButtons() {
    const { selectedOS } = this.state;

    return Object.keys(osTypes).map((name, index) => {
      const classSet = classNames({
        "button button-outline": true,
        active: name === selectedOS
      });

      return (
        <button
          className={classSet}
          key={index}
          onClick={this.handleSelectedOSChange.bind(this, name)}
        >
          {name}
        </button>
      );
    });
  }

  getContent() {
    return (

        <Trans render="p">
          Choose your operating system and follow the instructions. For any
          issues or questions, please refer to our{" "}

            documentation

          .
        </Trans>

{this.getOSButtons()}

        {this.getCliInstructions()}

    );
  }

  render() {
    const { footer, open, showFooter, title } = this.props;
    const header = (
      <ModalHeading>
        <Trans id={title} render="span" />
      </ModalHeading>
    );

    return (
      <Modal
        header={header}
        footer={footer}
        modalClass="modal"
        onClose={this.onClose}
        open={open}
        showHeader={true}
        showFooter={showFooter}
        subHeader={this.getSubHeader()}
      >
        {this.getContent()}
      </Modal>
    );
  }
}

CliInstallModal.propTypes = {
  title: PropTypes.string.isRequired,
  subHeaderContent: PropTypes.string,
  showFooter: PropTypes.bool.isRequired,
  footer: PropTypes.node,
  onClose: PropTypes.func.isRequired
};

module.exports = CliInstallModal;
<commit_msg>feat: update CLI URL in UI installation instructions<commit_after>import { Trans } from "@lingui/macro";
import { i18nMark } from "@lingui/react";

import browserInfo from "browser-info";
import classNames from "classnames";
import { Modal } from "reactjs-components";
import PropTypes from "prop-types";
import React from "react";
import { Icon } from "@dcos/ui-kit";
import { SystemIcons } from "@dcos/ui-kit/dist/packages/icons/dist/system-icons-enum";
import { iconSizeXs } from "@dcos/ui-kit/dist/packages/design-tokens/build/js/designTokens";

import ClickToSelect from "../ClickToSelect";
import MetadataStore from "../../stores/MetadataStore";
import ModalHeading from "../modals/ModalHeading";

const METHODS_TO_BIND = ["onClose"];
const osTypes = {
  Windows: "windows",
  "OS X": "darwin",
  Linux: "linux"
};

class CliInstallModal extends React.Component {
  constructor() {
    super(...arguments);

    let selectedOS = browserInfo().os;
    if (!Object.keys(osTypes).includes(selectedOS)) {
      selectedOS = "Linux";
    }

    this.state = { selectedOS };

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  handleSelectedOSChange(selectedOS) {
    this.setState({ selectedOS });
  }

  onClose() {
    this.props.onClose();
  }

  getSubHeader() {
    if (!this.props.subHeaderContent) {
      return false;
    }

    return (

        {this.props.subHeaderContent}

    );
  }

  getCliInstructions() {
    const hostname = global.location.hostname;
    const protocol = global.location.protocol.replace(/[^\w]/g, "");
    let port = "";
    if (global.location.port) {
      port = ":" + global.location.port;
    }
    const clusterUrl = `${protocol}://${hostname}${port}`;
    const { selectedOS } = this.state;

    // Starting from DC/OS >=2.0, users can stick to the "latest" CLI.
    // However on DC/OS 1.x we must use the correct CLI for the given version of DC/OS.
    let dcosVersion = MetadataStore.parsedVersion
    cliVersion = dcosVersion.substring(0, 2) == '1.' ? `dcos-${dcosVersion}` : "latest";

    const downloadUrl = `https://downloads.dcos.io/cli/releases/binaries/dcos/${osTypes[selectedOS]}/x86-64/${cliVersion}/dcos`;
    if (selectedOS === "Windows") {
      return this.getWindowsInstallInstruction(clusterUrl, downloadUrl);
    }

    const instructions = [
      `curl ${downloadUrl} -o dcos`,
      `chmod +x ./dcos`,
      `sudo mv dcos /usr/local/bin`,
      `dcos cluster setup ${clusterUrl}`,
      `dcos`
    ].filter(instruction => instruction !== undefined);

    return (

        <Trans render="p" className="short-bottom">
          Copy and paste the code snippet into the terminal:
        </Trans>

          <ClickToSelect>

              {instructions.join(" && \n")}

          </ClickToSelect>

    );
  }

  getWindowsInstallInstruction(clusterUrl, downloadUrl) {
    const steps = [
      `cd path/to/download/directory`,
      `dcos cluster setup ${clusterUrl}`,
      `dcos`
    ]
      .filter(instruction => instruction !== undefined)
      .map((instruction, index) => {
        const helpText =
          index === 0
            ? i18nMark("In Command Prompt, enter")
            : i18nMark("Enter");

        return (

            <Trans render="p" className="short-bottom" id={helpText} />

              <ClickToSelect>

                  {instruction}

              </ClickToSelect>

        );
      });

    return (

        <Trans render="li">
          Download and install:{" "}

            <Icon
              shape={SystemIcons.Download}
              size={iconSizeXs}
              color="currentColor"
            />
            Download dcos.exe

          .
        </Trans>
        {steps}

    );
  }

  getOSButtons() {
    const { selectedOS } = this.state;

    return Object.keys(osTypes).map((name, index) => {
      const classSet = classNames({
        "button button-outline": true,
        active: name === selectedOS
      });

      return (
        <button
          className={classSet}
          key={index}
          onClick={this.handleSelectedOSChange.bind(this, name)}
        >
          {name}
        </button>
      );
    });
  }

  getContent() {
    return (

        <Trans render="p">
          Choose your operating system and follow the instructions. For any
          issues or questions, please refer to our{" "}

            documentation

          .
        </Trans>

{this.getOSButtons()}

        {this.getCliInstructions()}

    );
  }

  render() {
    const { footer, open, showFooter, title } = this.props;
    const header = (
      <ModalHeading>
        <Trans id={title} render="span" />
      </ModalHeading>
    );

    return (
      <Modal
        header={header}
        footer={footer}
        modalClass="modal"
        onClose={this.onClose}
        open={open}
        showHeader={true}
        showFooter={showFooter}
        subHeader={this.getSubHeader()}
      >
        {this.getContent()}
      </Modal>
    );
  }
}

CliInstallModal.propTypes = {
  title: PropTypes.string.isRequired,
  subHeaderContent: PropTypes.string,
  showFooter: PropTypes.bool.isRequired,
  footer: PropTypes.node,
  onClose: PropTypes.func.isRequired
};

module.exports = CliInstallModal;
<|endoftext|>


<commit_before>import {UseCase} from 'almin'
import {Request} from 'superagent'

import * as actions from 'src/actions'
import {makeOAuthAPIRequester} from 'src/api/APIRequester'
import MastodonAPISpec from 'src/api/MastodonAPISpec'
import {OAuthApp, OAuthToken} from 'src/models'
import Database from 'src/infra/Database'

/**
 * codeからアカウントを認証する
 */
export default class AuthorizeAccountUseCase extends UseCase {
  constructor() {
    super()
  }

  /**
   * @override
   * @param {string} host
   * @param {string} code
   * @param {string} redirectUri
   * @return {object} tokenとaccount
   */
  async execute(host, code, redirectUri) {
    let app
    try {
      app = await OAuthApp.query.getByIndex('host', host)
    } catch(e) {
      throw new Error('cannot find OAuthApp')
    }

    // code -> tokenにする
    const tokenData = (await new Request('POST', `https://${host}/oauth/token`)
      .set('Accept', 'application/json')
      .query({
        client_id: app.client_id,
        client_secret: app.client_secret,
        code: code,
        grant_type: 'authorization_code',
        redirect_uri: redirectUri,
      })).body

    const token = new OAuthToken({
      host: host,
      ...tokenData,
    })
    Database.save(token)

    // get my info
    const requester = makeOAuthAPIRequester(
      MastodonAPISpec, {
        token,
        endpoint: `https://${host}/api/v1`,
        hooks: {
          response: (method, apiName, responseBody) => {
            return {host, ...responseBody}
          },
        },
      })
    const {entities, result} = await requester.verifyCredentials()
    token.attachAccount(entities.accounts[result])

    this.dispatch({
      type: actions.TOKEN_ADDED,
      token,
    })

    return {token, account: token.account}
  }
}
<commit_msg>アカウント追加時にエラーが出ていた<commit_after>import {UseCase} from 'almin'
import {Request} from 'superagent'

import * as actions from 'src/actions'
import {makeOAuthAPIRequester} from 'src/api/APIRequester'
import MastodonAPISpec from 'src/api/MastodonAPISpec'
import {OAuthApp, OAuthToken} from 'src/models'
import Database from 'src/infra/Database'

/**
 * codeからアカウントを認証する
 */
export default class AuthorizeAccountUseCase extends UseCase {
  constructor() {
    super()
  }

  /**
   * @override
   * @param {string} host
   * @param {string} code
   * @param {string} redirectUri
   * @return {object} tokenとaccount
   */
  async execute(host, code, redirectUri) {
    let app
    try {
      app = await OAuthApp.query.getByIndex('host', host)
    } catch(e) {
      throw new Error('cannot find OAuthApp')
    }

    // code -> tokenにする
    const tokenData = (await new Request('POST', `https://${host}/oauth/token`)
      .set('Accept', 'application/json')
      .query({
        client_id: app.client_id,
        client_secret: app.client_secret,
        code: code,
        grant_type: 'authorization_code',
        redirect_uri: redirectUri,
      })).body

    const token = new OAuthToken({
      host: host,
      ...tokenData,
    })
    Database.save(token)

    // get my info
    const requester = makeOAuthAPIRequester(
      MastodonAPISpec, {
        token,
        endpoint: `https://${host}/api/v1`,
        hooks: {
          response: (method, apiName, responseBody) => {
            return {result: {host, ...responseBody}}
          },
        },
      })
    const {entities, result} = await requester.verifyCredentials()
    token.attachAccount(entities.accounts[result])

    this.dispatch({
      type: actions.TOKEN_ADDED,
      token,
    })

    return {token, account: token.account}
  }
}
<|endoftext|>


<commit_before>$(document).ready(function(){

//define our team list!
var teams = [' #1 (1)', ' #2 (16)', ' #3 (8)', ' #4 (9)', ' #5 (5)', ' #6 (12)', ' #7 (4)', ' #8 (13)',
		' #9 (6)', ' #10 (11)', ' #11 (3)', ' #12 (14)', ' #13 (7)', ' #14 (10)', ' #15 (2)', ' #16 (15)',
' #17 (1)', ' #18 (16)', ' #19 (8)', ' #20 (9)', ' #21 (5)', ' #22 (12)', ' #23 (4)', ' #24 (13)',
		' #25 (6)', ' #26 (11)', ' #27 (3)', ' #28 (14)', ' #29 (7)', ' #30 (10)', ' #31 (2)', ' #32 (15)',
' #33 (1)', ' #34 (16)', ' #35 (8)', ' #36 (9)', ' #37 (5)', ' #38 (12)', ' #39 (4)', ' #40 (13)',
		' #41 (6)', ' #42 (11)', ' #43 (3)', ' #44 (14)', ' #45 (7)', ' #46 (10)', ' #47 (2)', ' #48 (15)',
' #49(1)', ' #50 (16)', ' #51 (8)', ' #52 (9)', ' #53 (5)', ' #54 (12)', ' #55 (4)', ' #56 (13)',
		' #57 (6)', ' #58 (11)', ' #59 (3)', ' #60 (14)', ' #61 (7)', ' #62 (10)', ' #63 (2)', ' #64 (15)', ]

var seeds = [1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15]

//set up inital matchups
var matchups = []
var seedMatchups = []
var results = []
//iterate through the list of teams, and pair them off into matchups 2 at a time
for (var n=0;n<teams.length;n+=2){
	var newMatchup = [teams[n], teams[n + 1]]
	var seedMatchup = [seeds[n], seeds[n+1]]

	console.log('creating matchup ' + newMatchup)
	//take our new matchup and add it to our list of matchups
	matchups.push(newMatchup);
	seedMatchups.push(seedMatchup);
}

//using these matchups, create a tournament object. It has no results yet.
var tournament = { teams: matchups, results: []}
console.log(tournament)
refreshBracket();

//on button press
$('#simulateRound').click(function(){
	if ($('td').hasClass('has-error')){
		console.log('Error with probabilities chart')
		alert('Please fix errors in probabilities chart. All values must be numbers between 0 and 1. You can refresh the page to reset the defaults.')
		return;
	}
	simulateRound()
	refreshBracket();
});
$('#simulateTournament').click(function(){
	if ($('td').hasClass('has-error')){
		console.log('Error with probabilities chart')
		alert('Please fix errors in probabilities chart. All values must be numbers between 0 and 1. You can refresh the page to reset the defaults.')
		return;
	}
	resetBracket();
	for (var x=0; x<6; x++){
		simulateRound();
	}
	refreshBracket();
})
$('#resetBracket').click(function() {resetBracket()})

//validation for inputs
$('input').change(function() {
    $input = $(this);
	n= $input.val()
	console.log(n)
	if (!isNaN(parseFloat(n)) && isFinite(n) && n <= 1 && n >= 0){
		console.log('Valid input')
		$input.parent('td').removeClass('has-error').addClass('has-success');
	} else {
		console.log('Invalid input')
		$input.parent('td').removeClass('has-success').addClass('has-error');
	}
})

function simulateRound() {
	console.log('Running round simulation')

	roundResults = {scores: [], nextSeeds: []};
	//iterate through each matchup
	for (var x=0; x<seedMatchups.length; x++){
		//get the seeds
		//get the probability for those seeds
		var highSeed = Math.min(seedMatchups[x][0], seedMatchups[x][1])
		var lowSeed = Math.max(seedMatchups[x][0], seedMatchups[x][1])
		var upsetPercentage = $('#'+ lowSeed + '-' + highSeed).val()
		console.log('High seed ' + highSeed + ' vs low seed ' + lowSeed + ' with upset % ' + upsetPercentage);
		//calculate who won
		//push results
		//push matchup and seeds
		var matchupResult = [1, 1]
		//Handle mirror matchups
		if (highSeed == lowSeed){
			console.log('Mirror matchup!')
			if (Math.random() > .5){
				roundResults.scores.push([1,2])
			} else {
				roundResults.scores.push([2,1])
			}
			roundResults.nextSeeds.push(highSeed)
		} else if (Math.random() > upsetPercentage)
		{
			matchupResult[seedMatchups[x].indexOf(highSeed)] = 2
			//console.log(matchupResult)
			roundResults.scores.push(matchupResult)
			roundResults.nextSeeds.push(highSeed)

		} else {
			matchupResult[seedMatchups[x].indexOf(lowSeed)] = 2
			//console.log(matchupResult)
			roundResults.scores.push(matchupResult)
			roundResults.nextSeeds.push(lowSeed)
		}
	}
	//set up next seedMatchups
	seedMatchups = []
	for (var x=0; x<roundResults.nextSeeds.length; x+=2){
		seedMatchups.push([roundResults.nextSeeds[x], roundResults.nextSeeds[x+1]])
	}
	//update results and bracket
	console.log(roundResults)
	results.push(roundResults.scores)
	tournament.results= results;
}

function resetBracket(){
	//reset tourney
	console.log('Resetting bracket');
	matchups = []
	seedMatchups = []
	results = []
	for (var n=0;n<teams.length;n+=2){
		var newMatchup = [teams[n], teams[n + 1]]
		var seedMatchup = [seeds[n], seeds[n+1]]
		console.log('creating matchup ' + newMatchup)
		matchups.push(newMatchup);
		seedMatchups.push(seedMatchup);
	}
	tournament = { teams: matchups, results: []}
	refreshBracket()
}

function refreshBracket() {
	var $bracket = $('#bracket');
	$bracket.empty()
    $bracket.bracket({
	  skipConsolationRound: true,
      init: tournament  })
  }

})<commit_msg>Adding the real teams<commit_after>$(document).ready(function(){

//define our team list!
var teams = ['(1) FLA', '(16) TBD', '(8) COLO', '(9) PITT', '(5) VCU', '(12) SFA', '(4) UCLA', '(13) TLSA',
		'(6) OSU', '(11) DAY', '(3) SYR', '(14) WMU', '(7) UNM', '(10) STAN', '(2) KU', '(15) EKY',
'(1) ARIZ', '(16) WEB', '(8) GONZ', '(9) OKST', '(5) OKLA', '(12) NDSU', '(4) SDSU', '(13) NMSU',
	'(6) BAY', '(11) NEB', '(3) CREI', '(14) ULL', '(7) ORE', '(10) BYU', '(2) WIS', '(15) AMER',
'(1) UVA', '(16) CCAR', '(8) MEM', ' (9) GW', '(5) CIN', ' (12) HARV', '(4) MSU', '(13) DEL',
		'(6) UNC', '(11) PROV', '(3) ISU', '(14) NCCU', '(7) CONN', '(10) JOES', '(2) VILL', '(15) MILW',
'(1) WICH', '(16) TBD', '(8) UK', '(9) KSU', '(5) SLU', '(12) TBD', '(4) LOU', '(13) MAN',
		'(6) MASS', '(11) TBD', '(3) DUKE', '(14) MER', '(7) TEX', '(10) ASU', '(2) MICH', '(15) WOF', ]

var seeds = [1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15,
			1, 16, 8, 9, 5, 12, 4, 13, 6, 11, 3, 14, 7, 10, 2, 15]

//set up inital matchups
var matchups = []
var seedMatchups = []
var results = []
//iterate through the list of teams, and pair them off into matchups 2 at a time
for (var n=0;n<teams.length;n+=2){
	var newMatchup = [teams[n], teams[n + 1]]
	var seedMatchup = [seeds[n], seeds[n+1]]

	console.log('creating matchup ' + newMatchup)
	//take our new matchup and add it to our list of matchups
	matchups.push(newMatchup);
	seedMatchups.push(seedMatchup);
}

//using these matchups, create a tournament object. It has no results yet.
var tournament = { teams: matchups, results: []}
console.log(tournament)
refreshBracket();

//on button press
$('#simulateRound').click(function(){
	if ($('td').hasClass('has-error')){
		console.log('Error with probabilities chart')
		alert('Please fix errors in probabilities chart. All values must be numbers between 0 and 1. You can refresh the page to reset the defaults.')
		return;
	}
	simulateRound()
	refreshBracket();
});
$('#simulateTournament').click(function(){
	if ($('td').hasClass('has-error')){
		console.log('Error with probabilities chart')
		alert('Please fix errors in probabilities chart. All values must be numbers between 0 and 1. You can refresh the page to reset the defaults.')
		return;
	}
	resetBracket();
	for (var x=0; x<6; x++){
		simulateRound();
	}
	refreshBracket();
})
$('#resetBracket').click(function() {resetBracket()})

//validation for inputs
$('input').change(function() {
    $input = $(this);
	n= $input.val()
	console.log(n)
	if (!isNaN(parseFloat(n)) && isFinite(n) && n <= 1 && n >= 0){
		console.log('Valid input')
		$input.parent('td').removeClass('has-error').addClass('has-success');
	} else {
		console.log('Invalid input')
		$input.parent('td').removeClass('has-success').addClass('has-error');
	}
})

function simulateRound() {
	console.log('Running round simulation')

	roundResults = {scores: [], nextSeeds: []};
	//iterate through each matchup
	for (var x=0; x<seedMatchups.length; x++){
		//get the seeds
		//get the probability for those seeds
		var highSeed = Math.min(seedMatchups[x][0], seedMatchups[x][1])
		var lowSeed = Math.max(seedMatchups[x][0], seedMatchups[x][1])
		var upsetPercentage = $('#'+ lowSeed + '-' + highSeed).val()
		console.log('High seed ' + highSeed + ' vs low seed ' + lowSeed + ' with upset % ' + upsetPercentage);
		//calculate who won
		//push results
		//push matchup and seeds
		var matchupResult = [1, 1]
		//Handle mirror matchups
		if (highSeed == lowSeed){
			console.log('Mirror matchup!')
			if (Math.random() > .5){
				roundResults.scores.push([1,2])
			} else {
				roundResults.scores.push([2,1])
			}
			roundResults.nextSeeds.push(highSeed)
		} else if (Math.random() > upsetPercentage)
		{
			matchupResult[seedMatchups[x].indexOf(highSeed)] = 2
			//console.log(matchupResult)
			roundResults.scores.push(matchupResult)
			roundResults.nextSeeds.push(highSeed)

		} else {
			matchupResult[seedMatchups[x].indexOf(lowSeed)] = 2
			//console.log(matchupResult)
			roundResults.scores.push(matchupResult)
			roundResults.nextSeeds.push(lowSeed)
		}
	}
	//set up next seedMatchups
	seedMatchups = []
	for (var x=0; x<roundResults.nextSeeds.length; x+=2){
		seedMatchups.push([roundResults.nextSeeds[x], roundResults.nextSeeds[x+1]])
	}
	//update results and bracket
	console.log(roundResults)
	results.push(roundResults.scores)
	tournament.results= results;
}

function resetBracket(){
	//reset tourney
	console.log('Resetting bracket');
	matchups = []
	seedMatchups = []
	results = []
	for (var n=0;n<teams.length;n+=2){
		var newMatchup = [teams[n], teams[n + 1]]
		var seedMatchup = [seeds[n], seeds[n+1]]
		console.log('creating matchup ' + newMatchup)
		matchups.push(newMatchup);
		seedMatchups.push(seedMatchup);
	}
	tournament = { teams: matchups, results: []}
	refreshBracket()
}

function refreshBracket() {
	var $bracket = $('#bracket');
	$bracket.empty()
    $bracket.bracket({
	  skipConsolationRound: true,
      init: tournament  })
  }

})<|endoftext|>


<commit_before>$(document).ready(function () {
  var bootcamps = ''
  $.getJSON('/json/bootcamps.json', function(data) {
    bootcamps = data;
  });
  var city = "";
  $("body").data("state", "stacked");
  $('#city-buttons').on("click", "button", function () {
    $(this).addClass('animated pulse');
    city = $(this).attr("id");
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
      }) + ', and making $_______, your true costs will be:');
    setTimeout(function () {
      $('#city-buttons').hide();
      $('#income').addClass('animated fadeIn').show();
    }, 1000);
  });
  $('#income').on("click", "button", function () {
    $(this).addClass('animated pulse');
    setTimeout(function () {
      $('#income').hide();
      $('#chart').addClass('animated fadeIn').show();
      $('#chart-controls').addClass('animated fadeIn').show();
      $('#explanation').addClass('animated fadeIn').show();
    }, 1000);
    var lastYearsIncome = parseInt($(this).attr("id"));
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
      }) + ', and making $' + lastYearsIncome.toString().replace(/0000$/, '0,000') + ', your true costs will be:');
    var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Est. Wage Garnishing'];
    bootcamps.forEach(function (camp) {
      var x0 = 0;
      if (camp.cities.indexOf(city) > -1) {
        weeklyHousing = 0;
      } else {
        weeklyHousing = +camp.housing;
      }
      camp.mapping = [{
        name: camp.name,
        label: 'Tuition / Est. Wage Garnishing',
        value: +camp.cost,
        x0: x0,
        x1: x0 += +camp.cost
      }, {
        name: camp.name,
        label: 'Financing Cost',
        value: +Math.floor(camp.cost * .09519),
        x0: +camp.cost,
        x1: camp.finance ? x0 += +Math.floor(camp.cost * .09519) : 0
      }, {
        name: camp.name,
        label: 'Housing Cost',
        value: +weeklyHousing * camp.weeks,
        x0: camp.finance ? +Math.floor(camp.cost * 1.09519) : camp.cost,
        x1: x0 += weeklyHousing * camp.weeks
      }, {
        name: camp.name,
        label: 'Lost Wages',
        value: +(Math.floor(camp.weeks * lastYearsIncome / 50)),
        x0: camp.finance ? +(Math.floor(camp.cost * 1.09519) + weeklyHousing * camp.weeks) : +camp.cost + weeklyHousing * camp.weeks,
        x1: x0 += +(Math.floor(camp.weeks * lastYearsIncome / 50))
      }];
      camp.total = camp.mapping[camp.mapping.length - 1].x1;
    });
    bootcamps.sort(function (a, b) {
      return a.total - b.total;
    });
    maxValue = 0;
    bootcamps.forEach(function (camp) {
      camp.mapping.forEach(function (elem) {
        if (elem.value > maxValue) {
          maxValue = elem.value;
        }
      });
    });
    var xStackMax = d3.max(bootcamps, function (d) {
        return d.total;
      }), //Scale for Stacked
      xGroupMax = bootcamps.map(function (camp) {
        return camp.mapping.reduce(function (a, b) {
          return a.value > b.value ? a.value : b.value;
        });
      }).reduce(function (a, b) {
        return a > b ? a : b;
      });
    var margin = {
        top: 30,
        right: 60,
        bottom: 50,
        left: 140
      },
      width = 800 - margin.left - margin.right,
      height = 1200 - margin.top - margin.bottom;
    var barHeight = 20;
    var xScale = d3.scale.linear()
      .domain([0, xStackMax])
      .rangeRound([0, width]);
    var y0Scale = d3.scale.ordinal()
      .domain(bootcamps.map(function (d) {
        return d.name;
      }))
      .rangeRoundBands([0, height], .1);
    var y1Scale = d3.scale.ordinal()
      .domain(categoryNames).rangeRoundBands([0, y0Scale.rangeBand()]);
    var color = d3.scale.ordinal()
      .range(["#215f1e", "#5f5c1e", "#1e215f", "#5c1e5f"])
      .domain(categoryNames);
    var svg = d3.select("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var selection = svg.selectAll(".series")
      .data(bootcamps)
      .enter().append("g")
      .attr("class", "series")
      .attr("transform", function (d) {
        return "translate(0," + y0Scale(d.name) + ")";
      });
    var rect = selection.selectAll("rect")
      .data(function (d) {
        return d.mapping;
      })
      .enter().append("rect")
      .attr("x", 0)
      .attr("width", 0)
      .attr("height", y0Scale.rangeBand())
      .style("fill", function (d) {
        return color(d.label);
      })
      .style("stroke", "white")
      .on("mouseover", function (d) {
        showPopover.call(this, d);
      })
      .on("mouseout", function (d) {
        removePopovers();
      });
    rect.transition()
      .delay(function (d, i) {
        return i * 10;
      })
      .attr("x", function (d) {
        return xScale(d.x0);
      })
      .attr("width", function (d) {
        return xScale((d.x1) - (d.x0));
      });
    d3.selectAll("#transform").on("click", function () {
      $('#transform').addClass('animated pulse');
      change();
      setTimeout(function () {
        $('#transform').removeClass('animated pulse');
      }, 1000);
    });

    d3.selectAll("#chart").on("click", function () {
      change();
    });

    function change() {
      if ($("body").data("state") === "stacked") {
        transitionGrouped();
        $("body").data("state", "grouped");
      } else {
        transitionStacked();
        $("body").data("state", "stacked");
      }
    }

    function transitionGrouped() {
      xScale.domain = ([0, xGroupMax]);
      rect.transition()
        .duration(500)
        .delay(function (d, i) {
          return i * 10;
        })
        .attr("width", function (d) {
          return xScale((d.x1) - (d.x0));
        })
        .transition()
        .attr("y", function (d) {
          return y1Scale(d.label);
        })
        .attr("x", 0)
        .attr("height", y1Scale.rangeBand())
    }

    function transitionStacked() {
      xScale.domain = ([0, xStackMax]);
      rect.transition()
        .duration(500)
        .delay(function (d, i) {
          return i * 10;
        })
        .attr("x", function (d) {
          return xScale(d.x0);
        })
        .transition()
        .attr("y", function (d) {
          return y0Scale(d.label);
        })
        .attr("height", y0Scale.rangeBand())
    }

    //axes
    var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom");
    var yAxis = d3.svg.axis()
      .scale(y0Scale)
      .orient("left");
    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .append("text")
      .attr("x", 300)
      .attr("y", 35)
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .text("Cost in $USD");
    //tooltips
    function removePopovers() {
      $('.popover').each(function () {
        $(this).remove();
      });
    }

    function showPopover(d) {
      $(this).popover({
        title: d.name,
        placement: 'auto top',
        container: 'body',
        trigger: 'manual',
        html: true,
        content: function () {
          return d.label +
            "
$" +
            d3.format(",")(d.value ? d.value : d.x1 - d.x0);
        }
      });
      $(this).popover('show')
    }

    //legends
    var legend = svg.selectAll(".legend")
      .data(categoryNames.slice().reverse())
      .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function (d, i) {
        return "translate(30," + i * y0Scale.rangeBand() * 1.1 + ")";
      });
    legend.append("rect")
      .attr("x", width - y0Scale.rangeBand())
      .attr("width", y0Scale.rangeBand())
      .attr("height", y0Scale.rangeBand())
      .style("fill", color)
      .style("stroke", "white");
    legend.append("text")
      .attr("x", width - y0Scale.rangeBand() * 1.2)
      .attr("y", 12)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function (d) {
        return d;
      });
  });
});
<commit_msg>Add missing semicolons to Calculator.js for consistency (#15257)<commit_after>$(document).ready(function () {
  var bootcamps = ''
  $.getJSON('/json/bootcamps.json', function(data) {
    bootcamps = data;
  });
  var city = "";
  $("body").data("state", "stacked");
  $('#city-buttons').on("click", "button", function () {
    $(this).addClass('animated pulse');
    city = $(this).attr("id");
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
      }) + ', and making $_______, your true costs will be:');
    setTimeout(function () {
      $('#city-buttons').hide();
      $('#income').addClass('animated fadeIn').show();
    }, 1000);
  });
  $('#income').on("click", "button", function () {
    $(this).addClass('animated pulse');
    setTimeout(function () {
      $('#income').hide();
      $('#chart').addClass('animated fadeIn').show();
      $('#chart-controls').addClass('animated fadeIn').show();
      $('#explanation').addClass('animated fadeIn').show();
    }, 1000);
    var lastYearsIncome = parseInt($(this).attr("id"));
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
      }) + ', and making $' + lastYearsIncome.toString().replace(/0000$/, '0,000') + ', your true costs will be:');
    var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Est. Wage Garnishing'];
    bootcamps.forEach(function (camp) {
      var x0 = 0;
      if (camp.cities.indexOf(city) > -1) {
        weeklyHousing = 0;
      } else {
        weeklyHousing = +camp.housing;
      }
      camp.mapping = [{
        name: camp.name,
        label: 'Tuition / Est. Wage Garnishing',
        value: +camp.cost,
        x0: x0,
        x1: x0 += +camp.cost
      }, {
        name: camp.name,
        label: 'Financing Cost',
        value: +Math.floor(camp.cost * .09519),
        x0: +camp.cost,
        x1: camp.finance ? x0 += +Math.floor(camp.cost * .09519) : 0
      }, {
        name: camp.name,
        label: 'Housing Cost',
        value: +weeklyHousing * camp.weeks,
        x0: camp.finance ? +Math.floor(camp.cost * 1.09519) : camp.cost,
        x1: x0 += weeklyHousing * camp.weeks
      }, {
        name: camp.name,
        label: 'Lost Wages',
        value: +(Math.floor(camp.weeks * lastYearsIncome / 50)),
        x0: camp.finance ? +(Math.floor(camp.cost * 1.09519) + weeklyHousing * camp.weeks) : +camp.cost + weeklyHousing * camp.weeks,
        x1: x0 += +(Math.floor(camp.weeks * lastYearsIncome / 50))
      }];
      camp.total = camp.mapping[camp.mapping.length - 1].x1;
    });
    bootcamps.sort(function (a, b) {
      return a.total - b.total;
    });
    maxValue = 0;
    bootcamps.forEach(function (camp) {
      camp.mapping.forEach(function (elem) {
        if (elem.value > maxValue) {
          maxValue = elem.value;
        }
      });
    });
    var xStackMax = d3.max(bootcamps, function (d) {
        return d.total;
      }), //Scale for Stacked
      xGroupMax = bootcamps.map(function (camp) {
        return camp.mapping.reduce(function (a, b) {
          return a.value > b.value ? a.value : b.value;
        });
      }).reduce(function (a, b) {
        return a > b ? a : b;
      });
    var margin = {
        top: 30,
        right: 60,
        bottom: 50,
        left: 140
      },
      width = 800 - margin.left - margin.right,
      height = 1200 - margin.top - margin.bottom;
    var barHeight = 20;
    var xScale = d3.scale.linear()
      .domain([0, xStackMax])
      .rangeRound([0, width]);
    var y0Scale = d3.scale.ordinal()
      .domain(bootcamps.map(function (d) {
        return d.name;
      }))
      .rangeRoundBands([0, height], .1);
    var y1Scale = d3.scale.ordinal()
      .domain(categoryNames).rangeRoundBands([0, y0Scale.rangeBand()]);
    var color = d3.scale.ordinal()
      .range(["#215f1e", "#5f5c1e", "#1e215f", "#5c1e5f"])
      .domain(categoryNames);
    var svg = d3.select("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var selection = svg.selectAll(".series")
      .data(bootcamps)
      .enter().append("g")
      .attr("class", "series")
      .attr("transform", function (d) {
        return "translate(0," + y0Scale(d.name) + ")";
      });
    var rect = selection.selectAll("rect")
      .data(function (d) {
        return d.mapping;
      })
      .enter().append("rect")
      .attr("x", 0)
      .attr("width", 0)
      .attr("height", y0Scale.rangeBand())
      .style("fill", function (d) {
        return color(d.label);
      })
      .style("stroke", "white")
      .on("mouseover", function (d) {
        showPopover.call(this, d);
      })
      .on("mouseout", function (d) {
        removePopovers();
      });
    rect.transition()
      .delay(function (d, i) {
        return i * 10;
      })
      .attr("x", function (d) {
        return xScale(d.x0);
      })
      .attr("width", function (d) {
        return xScale((d.x1) - (d.x0));
      });
    d3.selectAll("#transform").on("click", function () {
      $('#transform').addClass('animated pulse');
      change();
      setTimeout(function () {
        $('#transform').removeClass('animated pulse');
      }, 1000);
    });

    d3.selectAll("#chart").on("click", function () {
      change();
    });

    function change() {
      if ($("body").data("state") === "stacked") {
        transitionGrouped();
        $("body").data("state", "grouped");
      } else {
        transitionStacked();
        $("body").data("state", "stacked");
      }
    }

    function transitionGrouped() {
      xScale.domain = ([0, xGroupMax]);
      rect.transition()
        .duration(500)
        .delay(function (d, i) {
          return i * 10;
        })
        .attr("width", function (d) {
          return xScale((d.x1) - (d.x0));
        })
        .transition()
        .attr("y", function (d) {
          return y1Scale(d.label);
        })
        .attr("x", 0)
        .attr("height", y1Scale.rangeBand());
    }

    function transitionStacked() {
      xScale.domain = ([0, xStackMax]);
      rect.transition()
        .duration(500)
        .delay(function (d, i) {
          return i * 10;
        })
        .attr("x", function (d) {
          return xScale(d.x0);
        })
        .transition()
        .attr("y", function (d) {
          return y0Scale(d.label);
        })
        .attr("height", y0Scale.rangeBand());
    }

    //axes
    var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom");
    var yAxis = d3.svg.axis()
      .scale(y0Scale)
      .orient("left");
    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .append("text")
      .attr("x", 300)
      .attr("y", 35)
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .text("Cost in $USD");
    //tooltips
    function removePopovers() {
      $('.popover').each(function () {
        $(this).remove();
      });
    }

    function showPopover(d) {
      $(this).popover({
        title: d.name,
        placement: 'auto top',
        container: 'body',
        trigger: 'manual',
        html: true,
        content: function () {
          return d.label +
            "
$" +
            d3.format(",")(d.value ? d.value : d.x1 - d.x0);
        }
      });
      $(this).popover('show');
    }

    //legends
    var legend = svg.selectAll(".legend")
      .data(categoryNames.slice().reverse())
      .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function (d, i) {
        return "translate(30," + i * y0Scale.rangeBand() * 1.1 + ")";
      });
    legend.append("rect")
      .attr("x", width - y0Scale.rangeBand())
      .attr("width", y0Scale.rangeBand())
      .attr("height", y0Scale.rangeBand())
      .style("fill", color)
      .style("stroke", "white");
    legend.append("text")
      .attr("x", width - y0Scale.rangeBand() * 1.2)
      .attr("y", 12)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function (d) {
        return d;
      });
  });
});
<|endoftext|>


<commit_before>/** @jsx React.DOM */

function convertMinutes(minutes) {
  if (minutes == 0) {
    return "now";
  } else if (minutes < 60) {
    return minutes + "m ago";
  } else if (minutes < 1440) { // 60*24
    return Math.round(minutes/60) + "h " + (minutes%60) + "m ago";
  } else if (minutes < 10080) { // 60*24*7
    return Math.round(minutes/1440) + "d ago";
  } else {
    return Math.round(minutes/10080) + "w ago";
  }
}

var ChannelTable = React.createClass({
  mixins: [SetIntervalMixin],
  getInitialState: function() {
    return {streams: []};
  },
  componentDidMount: function() {
    this.dataUpdate();
    this.setInterval(this.dataUpdate, 5000);
  },
  dataUpdate: function() {
    var xhr = new XMLHttpRequest();
    xhr.open('get', document.URL + "api/get/data", true);
    xhr.onload = function() {
      var data = JSON.parse(xhr.responseText);
      this.setState({ streams: data.Streams });
    }.bind(this);
    xhr.send();
  },
  render: function() {
    var cells = [];
    var first = true;
    var firstCell;
    var avg = 0;
    this.state.streams.sort(function(a, b) {
      return parseInt(b.currkpm) - parseInt(a.currkpm);
    });

    var i = 1;
    var url = "";
    this.state.streams.forEach(function(stream) {
      var since = Math.round((Date.now() - Date.parse(stream.maxkpm_date))/60000);
      var sinceConvert = convertMinutes(since);
      if (stream.logo == "") {
        stream.logo = "http://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png";
      }
      url = "www.twitch.tv/" + stream.display_name;

      if (stream.maxkpm > 0) {
        stream.maxkpm_date = sinceConvert;
      } else {
        stream.maxkpm_date = 0;
      }

      if (stream.minutes > 0) {
        avg = (stream.kappa / stream.minutes).toFixed(2);
      } else {
        avg = 0;
      }
      if (first) {
        firstCell = <ChannelCell first={first} url={url} avg={avg} stream={stream} key={stream.display_name} />;
        first = false;
      } else {
        cells.push(<ChannelCell first={first} url={url} avg={avg} stream={stream} key={stream.display_name} />);
      }

      stream.display_name = i + ' ' + stream.display_name;
      i += 1;
    });
    return(
      React.createElement("div", {className: "cells"},
        firstCell,
        React.createElement("div", {className: "bar"}),
        React.createElement("div", {className: "channelTable"},
          cells
        )
      )
    );
  }
});

var ChannelCell = React.createClass({
  render: function() {
    var channelType;
    var contentStatic = <ChannelStatic
            displayName={this.props.stream.display_name}
            logo={this.props.stream.logo} />;
    var contentDynamic =
          <ChannelDynamic
            game={this.props.stream.game}
            viewers={this.props.stream.viewers}
            avg={this.props.avg}
            kappa={this.props.stream.kappa}
            maxkpm={this.props.stream.maxkpm}
            date={this.props.stream.maxkpm_date}
            currkpm={this.props.stream.currkpm} />;

    if (this.props.first) {
      channelType =

        {contentStatic}
        {contentDynamic}

;
    } else {
      channelType =

        {contentStatic}
        {contentDynamic}

;
    }

    return (

        {channelType}

    );
  }
});

var ChannelStatic = React.createClass({
  render: function() {
    return (

{this.props.displayName}

    );
  }
});

var ChannelDynamic = React.createClass({
  render: function() {
    return (

KPM: {this.props.currkpm}

AVG: {this.props.avg}

MAX: {this.props.maxkpm}

set: {this.props.date}

Kappa: {this.props.kappa}

{this.props.game}

Viewer: {this.props.viewers}

    );
  }
});

React.render(
  <ChannelTable />,
  document.getElementById('content')
);
<commit_msg>url fix<commit_after>/** @jsx React.DOM */

function convertMinutes(minutes) {
  if (minutes == 0) {
    return "now";
  } else if (minutes < 60) {
    return minutes + "m ago";
  } else if (minutes < 1440) { // 60*24
    return Math.round(minutes/60) + "h " + (minutes%60) + "m ago";
  } else if (minutes < 10080) { // 60*24*7
    return Math.round(minutes/1440) + "d ago";
  } else {
    return Math.round(minutes/10080) + "w ago";
  }
}

var ChannelTable = React.createClass({
  mixins: [SetIntervalMixin],
  getInitialState: function() {
    return {streams: []};
  },
  componentDidMount: function() {
    this.dataUpdate();
    this.setInterval(this.dataUpdate, 5000);
  },
  dataUpdate: function() {
    var xhr = new XMLHttpRequest();
    xhr.open('get', document.URL + "api/get/data", true);
    xhr.onload = function() {
      var data = JSON.parse(xhr.responseText);
      this.setState({ streams: data.Streams });
    }.bind(this);
    xhr.send();
  },
  render: function() {
    var cells = [];
    var first = true;
    var firstCell;
    var avg = 0;
    this.state.streams.sort(function(a, b) {
      return parseInt(b.currkpm) - parseInt(a.currkpm);
    });

    var i = 1;
    var url = "";
    this.state.streams.forEach(function(stream) {
      var since = Math.round((Date.now() - Date.parse(stream.maxkpm_date))/60000);
      var sinceConvert = convertMinutes(since);
      if (stream.logo == "") {
        stream.logo = "http://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png";
      }
      url = "http://www.twitch.tv/" + stream.display_name;

      if (stream.maxkpm > 0) {
        stream.maxkpm_date = sinceConvert;
      } else {
        stream.maxkpm_date = 0;
      }

      if (stream.minutes > 0) {
        avg = (stream.kappa / stream.minutes).toFixed(2);
      } else {
        avg = 0;
      }
      if (first) {
        firstCell = <ChannelCell first={first} url={url} avg={avg} stream={stream} key={stream.display_name} />;
        first = false;
      } else {
        cells.push(<ChannelCell first={first} url={url} avg={avg} stream={stream} key={stream.display_name} />);
      }

      stream.display_name = i + ' ' + stream.display_name;
      i += 1;
    });
    return(
      React.createElement("div", {className: "cells"},
        firstCell,
        React.createElement("div", {className: "bar"}),
        React.createElement("div", {className: "channelTable"},
          cells
        )
      )
    );
  }
});

var ChannelCell = React.createClass({
  render: function() {
    var channelType;
    var contentStatic = <ChannelStatic
            displayName={this.props.stream.display_name}
            logo={this.props.stream.logo} />;
    var contentDynamic =
          <ChannelDynamic
            game={this.props.stream.game}
            viewers={this.props.stream.viewers}
            avg={this.props.avg}
            kappa={this.props.stream.kappa}
            maxkpm={this.props.stream.maxkpm}
            date={this.props.stream.maxkpm_date}
            currkpm={this.props.stream.currkpm} />;

    if (this.props.first) {
      channelType =

        {contentStatic}
        {contentDynamic}

;
    } else {
      channelType =

        {contentStatic}
        {contentDynamic}

;
    }

    return (

        {channelType}

    );
  }
});

var ChannelStatic = React.createClass({
  render: function() {
    return (

{this.props.displayName}

    );
  }
});

var ChannelDynamic = React.createClass({
  render: function() {
    return (

KPM: {this.props.currkpm}

AVG: {this.props.avg}

MAX: {this.props.maxkpm}

set: {this.props.date}

Kappa: {this.props.kappa}

{this.props.game}

Viewer: {this.props.viewers}

    );
  }
});

React.render(
  <ChannelTable />,
  document.getElementById('content')
);
<|endoftext|>


<commit_before>const crypto = require('crypto');

function encrypt(data, password, algo = 'aes-256-cbc') {
  const password_hash = shaHash(password).slice(0, 32);
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(algo, password_hash, iv);
  const encData = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
  return iv.toString('hex') + ':' + encData;
}

function shaHash(password) {
  let password_hash = crypto
    .createHash('sha256')
    .update(password, 'utf-8')
    .digest('hex')
    .toUpperCase();
  return password_hash;
}

function decrypt(data, password, algo = 'aes-256-cbc') {
  const password_hash = shaHash(password).slice(0, 32);
  const [iv, encData] = data.split(':');
  const ivBuffer = Buffer.from(iv, 'hex');
  const decipher = crypto.createDecipheriv(algo, password_hash, ivBuffer);
  const decrypted =
    decipher.update(encData, 'hex', 'utf8') + decipher.final('utf8');
  return decrypted;
}

module.exports = {
  encrypt,
  decrypt
};
<commit_msg>WIP Converting to a buffer<commit_after>const crypto = require('crypto');

function encrypt(data, password, algo = 'aes-256-cbc') {
  const password_hash = Buffer.from(shaHash(password));
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(algo, password_hash, iv);
  const encData = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
  return iv.toString() + ':' + encData;
}

function shaHash(password) {
  let password_hash = crypto
    .createHash('sha256')
    .update(password, 'utf-8')
    .digest('hex')
    .toUpperCase();
  return password_hash;
}

function decrypt(data, password, algo = 'aes-256-cbc') {
  const password_hash = Buffer.form(shaHash(password));
  const [iv, encData] = data.split(':');
  const ivBuffer = Buffer.from(iv, 'hex');
  const decipher = crypto.createDecipheriv(algo, password_hash, ivBuffer);
  const decrypted =
    decipher.update(encData, 'hex', 'utf8') + decipher.final('utf8');
  return decrypted;
}

module.exports = {
  encrypt,
  decrypt
};
<|endoftext|>


<commit_before>

function capture(video, canvas, image, captureButton, stopButton, snapshotButton) {
	var ctx = canvas.getContext('2d');
	var localMediaStream = null;
	var track = null;

	captureButton.disabled = true;
	stopButton.disabled = false;
	snapshotButton.disabled = false;

	stopButton.onclick = function () {
		stop(video);
	};

	window.URL = window.URL || window.webkitURL;
	navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia ||
						  navigator.mozGetUserMedia || navigator.msGetUserMedia;

	var constraints = {
		video: true
	}

	var successCallback = function(mediaStream) {
		video.src = (window.URL && window.URL.createObjectURL(mediaStream)) || mediaStream;
		video.addEventListener("loadedmetadata", function(e) {
			video.style.display = "block";
			localMediaStream = mediaStream;
			track = localMediaStream.getTracks()[0];
			snapshotButton.onclick = function(event) {
				takePhoto();
				//Added code for saving image
				var dataURL = canvas.toDataURL("image/png");
				//console.log(dataURL);
				//window.open(dataURL, "toDataURL() image", "width=600, height=200");
				//var ajax = new XMLHttpRequest();
				//ajax.open("POST",'index.php',false);
				//ajax.setRequestHeader('Content-Type', 'application/upload');
				//ajax.send(dataURL);

				//Confirmation for photo
				notie.confirm('Do you want to use this as your Photo of the Day?', 'Yes', 'Cancel', function()
                {
                	var currentDate = new Date();
					var dd = currentDate.getDate();
					var mm = currentDate.getMonth(); //January is 0!
					var yyyy = currentDate.getFullYear();

					var images;

					if(localStorage.getItem('images')===null)
					{
						images = [];
					}
					else
					{
						images = JSON.parse(localStorage.getItem('images'));
					}

                	//dataURL.replace(/^data:image\/(png|jpg);base64,/,"");
					//localStorage.setItem('image2', dataURL);
					if(localStorage.getItem('images')===null)
					{
						var newPhoto = new Object();
						newPhoto["id"] = "image"+0;
						newPhoto["image"] = dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["day"] = dd;
						newPhoto["month"] = mm;
						newPhoto["year"] = yyyy;
						newPhoto["description"] = "";
						//var newImage = new Image();
						//newImage.src = dataURL;
						images.push(newPhoto);
						//console.log(JSON.stringify(images));
						localStorage.setItem('images', JSON.stringify(images));
					}
					else if((dd !== images[images.length-1]["day"]) && (mm !== images[images.length-1]["month"]) && (yyyy !== images[images.length-1]["year"]))
					{
						var newPhoto = new Object();
						newPhoto["id"] = "image"+(images.length);
						newPhoto["image"] = dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["day"] = dd;
						newPhoto["month"] = mm;
						newPhoto["year"] = yyyy;
						newPhoto["description"] = "";
						//console.log(images.src);
						//var newImage = new Image();
						//newImage.src = dataURL;
						images.push(newPhoto);
						//console.log(images);
						//console.log(JSON.stringify(images));
						localStorage.setItem('images', JSON.stringify(images));
					}
					else
					{
						notie.alert(3, "Error!
 You've already taken your daily photo for today!
Come back tomorrow!" , 3);
						console.log("DENIED");
					}
					var data1;
			      	/*$.getJSON("images.json", function(data)
			      	{
			       	 	//console.log('My JSON data: ', data);
			        	//$('#myData').text(JSON.stringify(data))

			        	console.log(data);
						var idN = "image"+data.images.length++;

						var newPhoto = new Object();
						newPhoto["id"] = idN;
						newPhoto["image"] = "data:image/png;base64," + dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["date"] = Date();
						newPhoto["description"] = "";

						data["images"].push(newPhoto);
						console.log(data);
			      	});*/

					//COOKIE ATTEMPT
					/*if( typeof Cookies.getJSON('images') === 'undefined')
					{
						var imagesJSON = {
								"id": "image" + 0,
								"image": dataURL, //PROBLEM: dataURL too big?
								"thumb": "thumb-01.jpg"
						}
						Cookies.set('images', imagesJSON);
						console.log(Cookies.getJSON());
					}
					else
					{
						var imagesJSON = Cookies.getJSON('images');
						var newImage = {
							"id": "image"+(++imagesJSON.images.length),
							"image": dataURL,
							"thumb": "thumb-01.jpg"
						}
						imagesJSON.push(newImage);
						console.log("UPDATED NE: " + imagesJSON);
						Cookies.set('images', imagesJSON);
					}*/

                	notie.alert(1, 'Good choice!', 2);
                });
			}
		});
	};

	var errorCallback = function() {
		console.log("failure to get media");
	};

	var takePhoto = function () {
		ctx.drawImage(video, 0, 0, 320, 240);
		canvas.style.display = "block";
		showImage();
	};

	var showImage = function () {
		image.src = canvas.toDataURL('image/webp');
		image.style.display = "none";
	};

	var stop = function () {
		if (localMediaStream) {
			track.stop(); /* TODO: it doesn't work in Opera Mobile 12 */
		}

		captureButton.disabled = false;
		stopButton.disabled = true;
		snapshotButton.disabled = true;
	};

	if (navigator.getUserMedia) {
		navigator.getUserMedia(constraints, successCallback, errorCallback);
	} else {
		console.log("getUserMedia not supported");
	}
}

function getConfirmation(){
   var retVal = confirm("Do you want to use this photo for your Photo of the Day?");
   if( retVal == true ){
      //document.write ("User wants to use photo!");
      return true;
   }
   else{
      //document.write ("User does not want to use photo!");
      return false;
   }
}

function upload(file) {
  var form = new FormData(),
      xhr = new XMLHttpRequest();

  form.append('image', file);
  xhr.open('post', 'server.php', true);
  xhr.send(form);
}

function init() {
	var video = document.querySelector('video#getUserMedia');
	var canvas = document.querySelector('#canvas');
	var snapshot = document.querySelector('#snapshot');
	var captureButton = document.querySelector('#captureButton');
	var stopButton = document.querySelector('#stopButton');
	var snapshotButton = document.querySelector('#snapshotButton');

	captureButton.onclick = function () {
		capture(video, canvas, snapshot, captureButton, stopButton, snapshotButton);
	};
}<commit_msg>fixed buttons on daily photo page<commit_after>

function capture(video, canvas, image, captureButton, stopButton, snapshotButton) {
	var ctx = canvas.getContext('2d');
	var localMediaStream = null;
	var track = null;

	captureButton.disabled = true;
	stopButton.disabled = false;
	snapshotButton.disabled = false;

	stopButton.onclick = function () {
		stop(video);
	};

	window.URL = window.URL || window.webkitURL;
	navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia ||
						  navigator.mozGetUserMedia || navigator.msGetUserMedia;

	var constraints = {
		video: true
	}

	var successCallback = function(mediaStream) {
		video.src = (window.URL && window.URL.createObjectURL(mediaStream)) || mediaStream;
		video.addEventListener("loadedmetadata", function(e) {
			video.style.display = "block";
			localMediaStream = mediaStream;
			track = localMediaStream.getTracks()[0];
			snapshotButton.onclick = function(event) {
				takePhoto();
				//Added code for saving image
				var dataURL = canvas.toDataURL("image/png");
				//console.log(dataURL);
				//window.open(dataURL, "toDataURL() image", "width=600, height=200");
				//var ajax = new XMLHttpRequest();
				//ajax.open("POST",'index.php',false);
				//ajax.setRequestHeader('Content-Type', 'application/upload');
				//ajax.send(dataURL);

				//Confirmation for photo
				notie.confirm('Do you want to use this as your Photo of the Day?', 'Yes', 'Cancel', function()
                {
                	var currentDate = new Date();
					var dd = currentDate.getDate();
					var mm = currentDate.getMonth(); //January is 0!
					var yyyy = currentDate.getFullYear();

					var images;

					if(localStorage.getItem('images')===null)
					{
						images = [];
					}
					else
					{
						images = JSON.parse(localStorage.getItem('images'));
					}

                	//dataURL.replace(/^data:image\/(png|jpg);base64,/,"");
					//localStorage.setItem('image2', dataURL);
					if(localStorage.getItem('images')===null)
					{
						var newPhoto = new Object();
						newPhoto["id"] = "image"+0;
						newPhoto["image"] = dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["day"] = dd;
						newPhoto["month"] = mm;
						newPhoto["year"] = yyyy;
						newPhoto["description"] = "";
						//var newImage = new Image();
						//newImage.src = dataURL;
						images.push(newPhoto);
						//console.log(JSON.stringify(images));
						localStorage.setItem('images', JSON.stringify(images));
					}
					else if((dd !== images[images.length-1]["day"]) && (mm !== images[images.length-1]["month"]) && (yyyy !== images[images.length-1]["year"]))
					{
						var newPhoto = new Object();
						newPhoto["id"] = "image"+(images.length);
						newPhoto["image"] = dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["day"] = dd;
						newPhoto["month"] = mm;
						newPhoto["year"] = yyyy;
						newPhoto["description"] = "";
						//console.log(images.src);
						//var newImage = new Image();
						//newImage.src = dataURL;
						images.push(newPhoto);
						//console.log(images);
						//console.log(JSON.stringify(images));
						localStorage.setItem('images', JSON.stringify(images));
					}
					else
					{
						notie.alert(3, "Error!
 You've already taken your daily photo for today!
Come back tomorrow!" , 3);
						console.log("DENIED");
					}
					var data1;
			      	/*$.getJSON("images.json", function(data)
			      	{
			       	 	//console.log('My JSON data: ', data);
			        	//$('#myData').text(JSON.stringify(data))

			        	console.log(data);
						var idN = "image"+data.images.length++;

						var newPhoto = new Object();
						newPhoto["id"] = idN;
						newPhoto["image"] = "data:image/png;base64," + dataURL;
						newPhoto["thumb"] = "thumb-01.jpg";
						newPhoto["date"] = Date();
						newPhoto["description"] = "";

						data["images"].push(newPhoto);
						console.log(data);
			      	});*/

					//COOKIE ATTEMPT
					/*if( typeof Cookies.getJSON('images') === 'undefined')
					{
						var imagesJSON = {
								"id": "image" + 0,
								"image": dataURL, //PROBLEM: dataURL too big?
								"thumb": "thumb-01.jpg"
						}
						Cookies.set('images', imagesJSON);
						console.log(Cookies.getJSON());
					}
					else
					{
						var imagesJSON = Cookies.getJSON('images');
						var newImage = {
							"id": "image"+(++imagesJSON.images.length),
							"image": dataURL,
							"thumb": "thumb-01.jpg"
						}
						imagesJSON.push(newImage);
						console.log("UPDATED NE: " + imagesJSON);
						Cookies.set('images', imagesJSON);
					}*/

                	notie.alert(1, 'Good choice!', 2);
                });
			}
		});
	};

	var errorCallback = function() {
		console.log("failure to get media");
	};

	var takePhoto = function () {
		ctx.drawImage(video, 0, 0, 320, 240);
		canvas.style.display = "block";
		showImage();
	};

	var showImage = function () {
		image.src = canvas.toDataURL('image/webp');
		image.style.display = "none";
	};

	var stop = function () {
		if (localMediaStream) {
			track.stop(); /* TODO: it doesn't work in Opera Mobile 12 */
		}

		captureButton.disabled = false;
		stopButton.disabled = true;
		snapshotButton.disabled = true;
		$(captureButton).fadeIn();
		$(stopButton).fadeOut();
	};

	if (navigator.getUserMedia) {
		navigator.getUserMedia(constraints, successCallback, errorCallback);
	} else {
		console.log("getUserMedia not supported");
	}
}

function getConfirmation(){
   var retVal = confirm("Do you want to use this photo for your Photo of the Day?");
   if( retVal == true ){
      //document.write ("User wants to use photo!");
      return true;
   }
   else{
      //document.write ("User does not want to use photo!");
      return false;
   }
}

function upload(file) {
  var form = new FormData(),
      xhr = new XMLHttpRequest();

  form.append('image', file);
  xhr.open('post', 'server.php', true);
  xhr.send(form);
}

function init() {
	var video = document.querySelector('video#getUserMedia');
	var canvas = document.querySelector('#canvas');
	var snapshot = document.querySelector('#snapshot');
	var captureButton = document.querySelector('#captureButton');
	var stopButton = document.querySelector('#stopButton');
	var snapshotButton = document.querySelector('#snapshotButton');

	captureButton.onclick = function () {
		$(captureButton).fadeOut();
		$(stopButton).fadeIn();
		capture(video, canvas, snapshot, captureButton, stopButton, snapshotButton);
	};
}<|endoftext|>


<commit_before>'use strict';

/* Directives */
var directives = angular.module('myApp.directives', []);

directives.directive('error', function ($route, $rootScope, $location) {
    return {
        scope: {
            'errorText': '@'
        },
        restrict: 'E',
        templateUrl: '/partials/directives/error.html',
        link: function (scope, element, attrs) {
            scope.retry = function () {
                $route.reload();
            };

            var history = [];

            $rootScope.$on('$routeChangeSuccess', function () {
                history.push($location.$$path);
            });

            scope.goBack = function () {
                var prevUrl = history.length > 1 ? history.splice(-2)[0] : "/";
                $location.path(prevUrl);
            }
        }
    }
});<commit_msg>Cleanup.<commit_after>'use strict';

/* Directives */
var directives = angular.module('myApp.directives', []);

directives.directive('error', function ($route, $rootScope, $location) {
    return {
        scope: {
            'errorText': '@'
        },
        restrict: 'E',
        templateUrl: '/partials/directives/error.html',
        link: function (scope) {
            scope.retry = function () {
                $route.reload();
            };

            var history = [];

            $rootScope.$on('$routeChangeSuccess', function () {
                history.push($location.$$path);
            });

            scope.goBack = function () {
                var prevUrl = history.length > 1 ? history.splice(-2)[0] : "/";
                $location.path(prevUrl);
            }
        }
    }
});<|endoftext|>


<commit_before>const Joi = require('joi');
const Serialization = require('../serialization');
const {DatabaseConnector} = require('cloud-core');

function upsertMetadata(account, objectId, objectType, pluginId, version, data) {
  return DatabaseConnector.forShared().then(({Metadata}) => {
    return Metadata.find({
      where: {
        accountId: account.id,
        objectId: objectId,
        objectType: objectType,
        pluginId: pluginId,
      },
    }).then((existing) => {
      if (existing) {
        if (existing.version / 1 !== version / 1) {
          return Promise.reject(new Error("Version Conflict"));
        }
        existing.data = data;
        return existing.save();
      }
      return Metadata.create({
        accountId: account.id,
        objectId: objectId,
        objectType: objectType,
        pluginId: pluginId,
        version: 0,
        data: data,
      })
    })
  })
}

module.exports = (server) => {
  server.route({
    method: 'GET',
    path: `/metadata`,
    config: {
      description: `metadata`,
      notes: 'Notes go here',
      tags: ['metadata'],
      validate: {
        query: {
          limit: Joi.number().integer().min(1).max(2000).default(100),
          offset: Joi.number().integer().min(0).default(0),
        },
      },
      response: {
        schema: Joi.array().items(
          Serialization.jsonSchema('Metadata')
        ),
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;

      DatabaseConnector.forShared().then(({Metadata}) => {
        Metadata.findAll({
          where: {
            accountId: account.id,
            limit: request.query.limit,
            offset: request.query.offset,
          },
        }).then((items) => {
          reply(Serialization.jsonStringify(items));
        })
      })
    },
  });

  server.route({
    method: ['PUT', 'POST'],
    path: `/metadata/{objectId}/{pluginId}`,
    config: {
      description: `Update metadata`,
      tags: ['metadata'],
      validate: {
        params: {
          objectId: Joi.string(),
          pluginId: Joi.string(),
        },
        payload: {
          objectType: Joi.string(),
          version: Joi.number().integer(),
          value: Joi.string(),
        },
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;
      const {version, value, objectType} = request.payload;
      const {pluginId, objectId} = request.params;

      upsertMetadata(account, objectId, objectType, pluginId, version, JSON.parse(value))
      .then((metadata) => {
        reply(Serialization.jsonStringify(metadata));
      })
      .catch((err) => {
        reply({error: err.toString()}).code(409);
      })
    },
  })

  server.route({
    method: 'DELETE',
    path: `/metadata/{objectId}/{pluginId}`,
    config: {
      description: `Delete metadata`,
      tags: ['metadata'],
      validate: {
        params: {
          objectId: Joi.number().integer(),
          pluginId: Joi.string(),
        },
        payload: {
          objectType: Joi.string(),
          version: Joi.number().integer(),
        },
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;
      const {version, objectType} = request.payload;
      const {pluginId, objectId} = request.params;

      upsertMetadata(account, objectId, objectType, pluginId, version, null)
      .then((metadata) => {
        reply(Serialization.jsonStringify(metadata));
      })
      .catch((err) => {
        reply({error: err.toString()}).code(409);
      })
    },
  })
};
<commit_msg>[cloud-api] Require metadata payload params, value instead of data<commit_after>const Joi = require('joi');
const Serialization = require('../serialization');
const {DatabaseConnector} = require('cloud-core');

function upsertMetadata(account, objectId, objectType, pluginId, version, value) {
  return DatabaseConnector.forShared().then(({Metadata}) => {
    return Metadata.find({
      where: {
        accountId: account.id,
        objectId: objectId,
        objectType: objectType,
        pluginId: pluginId,
      },
    }).then((existing) => {
      if (existing) {
        if (existing.version / 1 !== version / 1) {
          return Promise.reject(new Error("Version Conflict"));
        }
        existing.value = value;
        return existing.save();
      }
      return Metadata.create({
        accountId: account.id,
        objectId: objectId,
        objectType: objectType,
        pluginId: pluginId,
        version: 0,
        value: value,
      })
    })
  })
}

module.exports = (server) => {
  server.route({
    method: 'GET',
    path: `/metadata`,
    config: {
      description: `metadata`,
      notes: 'Notes go here',
      tags: ['metadata'],
      validate: {
        query: {
          limit: Joi.number().integer().min(1).max(2000).default(100),
          offset: Joi.number().integer().min(0).default(0),
        },
      },
      response: {
        schema: Joi.array().items(
          Serialization.jsonSchema('Metadata')
        ),
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;

      DatabaseConnector.forShared().then(({Metadata}) => {
        Metadata.findAll({
          where: {
            accountId: account.id,
            limit: request.query.limit,
            offset: request.query.offset,
          },
        }).then((items) => {
          reply(Serialization.jsonStringify(items));
        })
      })
    },
  });

  server.route({
    method: ['PUT', 'POST'],
    path: `/metadata/{objectId}/{pluginId}`,
    config: {
      description: `Update metadata`,
      tags: ['metadata'],
      validate: {
        params: {
          objectId: Joi.string(),
          pluginId: Joi.string(),
        },
        payload: {
          objectType: Joi.string().required(),
          version: Joi.number().integer().required(),
          value: Joi.string().required(),
        },
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;
      const {version, value, objectType} = request.payload;
      const {pluginId, objectId} = request.params;

      upsertMetadata(account, objectId, objectType, pluginId, version, JSON.parse(value))
      .then((metadata) => {
        reply(Serialization.jsonStringify(metadata));
      })
      .catch((err) => {
        reply({error: err.toString()}).code(409);
      })
    },
  })

  server.route({
    method: 'DELETE',
    path: `/metadata/{objectId}/{pluginId}`,
    config: {
      description: `Delete metadata`,
      tags: ['metadata'],
      validate: {
        params: {
          objectId: Joi.number().integer(),
          pluginId: Joi.string(),
        },
        payload: {
          objectType: Joi.string(),
          version: Joi.number().integer(),
        },
      },
    },
    handler: (request, reply) => {
      const {account} = request.auth.credentials;
      const {version, objectType} = request.payload;
      const {pluginId, objectId} = request.params;

      upsertMetadata(account, objectId, objectType, pluginId, version, null)
      .then((metadata) => {
        reply(Serialization.jsonStringify(metadata));
      })
      .catch((err) => {
        reply({error: err.toString()}).code(409);
      })
    },
  })
};
<|endoftext|>