From e69a756aa9ef9ee9865c6c2f39949dbd59569e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Mon, 18 Sep 2023 11:22:35 +0200 Subject: [PATCH 01/78] feat: using getImageURL --- components/cms-modern/Image/Image.tsx | 4 ++-- .../ProductContent/ProductContent.tsx | 3 ++- .../Search/SearchResultsListing.tsx | 3 ++- .../ShoppableImage/ShoppableImage.tsx | 6 ++---- .../CuratedProductGridCard.tsx | 6 +++--- components/cms/ProductGrid/ProductGrid.tsx | 3 ++- .../product/ProductCard/ProductCard.tsx | 5 +++-- .../ProductMediaViewer/ProductMediaViewer.tsx | 19 ++++++++++--------- utils/getImageURL.ts | 7 ++++++- 9 files changed, 32 insertions(+), 24 deletions(-) diff --git a/components/cms-modern/Image/Image.tsx b/components/cms-modern/Image/Image.tsx index 195c1026..bbea0a0f 100644 --- a/components/cms-modern/Image/Image.tsx +++ b/components/cms-modern/Image/Image.tsx @@ -1,6 +1,7 @@ import React, { FC } from 'react' import { CmsContent } from '@lib/cms/CmsContent'; import { Box } from '@mui/material'; +import { getImageURL } from '@utils/getImageURL'; type Props = { image: any; @@ -87,8 +88,7 @@ const Image: FC = ({ if (roundel && roundel[0] && roundel[0].roundel && roundel[0].roundelPosition && roundel[0].roundelRatio) { queryString += `&$roundel$&${getRoundelConfig(roundel)}` } - queryString += '&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40' - return `${baseUrl}?${queryString}`; + return getImageURL(`${baseUrl}?${queryString}`); }; const source = ({ minWidth, maxWidth, width, highDensityWidth, format, poiAspect }: any) => { diff --git a/components/cms-modern/ProductContent/ProductContent.tsx b/components/cms-modern/ProductContent/ProductContent.tsx index c1867c9b..c202cb00 100644 --- a/components/cms-modern/ProductContent/ProductContent.tsx +++ b/components/cms-modern/ProductContent/ProductContent.tsx @@ -4,6 +4,7 @@ import ReactMarkdown from 'markdown-to-jsx'; import { ContentBlock } from '@components/cms-modern'; import { Box, Link, Typography } from '@mui/material'; import { nanoid } from 'nanoid' +import { getImageURL } from '@utils/getImageURL'; type Props = { } & CmsContent; @@ -65,7 +66,7 @@ const Text: FC = ({ return ( data && {data.name} diff --git a/components/cms-modern/Search/SearchResultsListing.tsx b/components/cms-modern/Search/SearchResultsListing.tsx index 8110a0d5..ecbde1f0 100644 --- a/components/cms-modern/Search/SearchResultsListing.tsx +++ b/components/cms-modern/Search/SearchResultsListing.tsx @@ -1,5 +1,6 @@ import React from 'react'; import SearchIcon from './SearchIcon'; +import { getImageURL } from '@utils/getImageURL'; interface Props { searchTerm: any; @@ -34,7 +35,7 @@ const SearchResultsListing: React.FC = (props) => { if (variants[0].images[0] && variants[0].images[0].url){ firstImage = variants[0].images[0].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if(firstImage.indexOf('cdn.media.amplience.net') > 0){ - firstImage += '?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40&w=50&h=50&upscale=false&unsharp=0,1,1,7' + firstImage = getImageURL(firstImage) } } } diff --git a/components/cms-modern/ShoppableImage/ShoppableImage.tsx b/components/cms-modern/ShoppableImage/ShoppableImage.tsx index f5b44247..1033aa8f 100644 --- a/components/cms-modern/ShoppableImage/ShoppableImage.tsx +++ b/components/cms-modern/ShoppableImage/ShoppableImage.tsx @@ -14,6 +14,7 @@ import { useWindowContext } from '../../core/WithWindowContext/WindowContext'; import clsx from 'clsx'; import { CircularProgress, Tooltip } from '@mui/material'; import Link from 'next/link'; +import { getImageURL } from '@utils/getImageURL'; type Props = { shoppableImage: any; @@ -228,10 +229,7 @@ const ShoppableImage: FC = ({ let image: JSX.Element | undefined; let src = "invalid"; if (shoppableImage && shoppableImage.image.id) { - const imageHost = shoppableImage.image.defaultHost; - src = `https://${imageHost}/i/${shoppableImage.image.endpoint}/${encodeURIComponent( - shoppableImage.image.name - )}?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40`; + src = getImageURL(shoppableImage.image) image = ( ({ root: { @@ -83,9 +84,8 @@ const CuratedProductGridCard: React.SFC = (props) => { } let imageUrl = result.overrides?.image - ? `https://${result.overrides.image?.defaultHost}/i/${result.overrides.image?.endpoint}/${result.overrides.image?.name}` - : `${result.variants[0].images[0].url}`; - imageUrl += '?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40&w=540&h=812' + ? getImageURL(result.overrides.image, {width: 540, height: 812}) + : getImageURL(result.variants[0].images[0].url, {width: 540, height: 812}) return ( diff --git a/components/cms/ProductGrid/ProductGrid.tsx b/components/cms/ProductGrid/ProductGrid.tsx index 9559e0a2..db6d80ff 100644 --- a/components/cms/ProductGrid/ProductGrid.tsx +++ b/components/cms/ProductGrid/ProductGrid.tsx @@ -7,6 +7,7 @@ import { useUserContext } from '@lib/user/UserContext'; import { Category, CommerceAPI, Product } from '@amplience/dc-integration-middleware'; import { commerceApi } from '@pages/api' import { useECommerce } from '@components/core/Masthead/ECommerceContext'; +import { getImageURL } from '@utils/getImageURL'; type Props = { } & CmsContent; @@ -83,7 +84,7 @@ const ProductGrid: FC = ({ if (images[0] && images[0].url) { firstImage = images[0].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if (firstImage.indexOf('cdn.media.amplience.net') > 0) { - firstImage += '?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40&w=540&upscale=false' + firstImage = getImageURL(firstImage, {width: 540}) } } } diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 939496e4..49c1a03a 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -6,6 +6,7 @@ import { useCmsContext } from '@lib/cms/CmsContext'; import { Product } from '@amplience/dc-integration-middleware'; import _ from 'lodash' import { withStyles, WithStyles } from '@mui/styles' +import { getImageURL } from '@utils/getImageURL'; const styles = (theme: Theme) => ({ root: { @@ -110,13 +111,13 @@ const ProductCardSkeleton: React.SFC = (props) => { firstImage = variant.images[0].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if(firstImage.indexOf('cdn.media.amplience.net') > 0){ - firstImage += '?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40&w=540&h=812' + firstImage = getImageURL(firstImage, {width: 540, height: 812}) } } if (variant.images[1] && variant.images[1].url){ secondImage = variant.images[1].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if(secondImage.indexOf('cdn.media.amplience.net') > 0){ - secondImage += '?fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40&w=540&h=812' + secondImage = getImageURL(firstImage, {width: 540, height: 812}) } } } diff --git a/components/product/ProductMediaViewer/ProductMediaViewer.tsx b/components/product/ProductMediaViewer/ProductMediaViewer.tsx index 150242ac..9dccc99b 100644 --- a/components/product/ProductMediaViewer/ProductMediaViewer.tsx +++ b/components/product/ProductMediaViewer/ProductMediaViewer.tsx @@ -5,6 +5,7 @@ import { useProduct } from '../WithProduct/WithProduct'; import ImageGallery from 'react-image-gallery'; import _ from 'lodash' import { withStyles, WithStyles } from '@mui/styles' +import { getImageURL } from '@utils/getImageURL'; const styles = (theme: Theme) => ({ }); @@ -50,18 +51,18 @@ const ProductMediaViewer: React.FunctionComponent = (props) => { view: variant, secure: true, templates: { - thumb: 'w=85&h=85&qlt=65&unsharp=0,1,1,7&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', + thumb: 'w=85&h=85&qlt=65&unsharp=0,1,1,7', desktop: { - main: 'w=600&qlt=75&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', - mainRetina: 'w=1200&qlt=75&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', + main: 'w=600&qlt=75&upscale=false', + mainRetina: 'w=1200&qlt=75&upscale=false', }, desktopFull: { - main: 'w=1000&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', - mainRetina: 'w=2000&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', + main: 'w=1000&upscale=false', + mainRetina: 'w=2000&upscale=false', }, mobile: { - main: 'w=500&h=500&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', - mainRetina: 'w=1000&h=1000&upscale=false&fmt=auto&qlt=default&fmt.jpeg.qlt=75&fmt.webp.qlt=60&fmt.jp2.qlt=40', + main: 'w=500&h=500&upscale=false', + mainRetina: 'w=1000&h=1000&upscale=false', }, }, ampConfigs: { @@ -95,8 +96,8 @@ const ProductMediaViewer: React.FunctionComponent = (props) => { else { return ( ({ - original: image.url, - thumbnail: image.thumb || image.url + original: getImageURL(image.url), + thumbnail: getImageURL(image.thumb || image.url) })), 'original')} /> ); } diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 8c0c64f8..675ffc1c 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -147,9 +147,14 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran query.push('fmt.jpeg.qlt=75') query.push('fmt.webp.qlt=60') query.push('fmt.jp2.qlt=40') + query.push('fmt.avif.qlt=60') if (query.length > 0) { - url += `?${query.join('&')}`; + if (url.indexOf('?') > -1) { + url += `&${query.join('&')}`; + } else { + url += `?${query.join('&')}`; + } } return url; From c3c9dfac13ca12c18f8fecd2273ab08d49461c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Mon, 18 Sep 2023 11:47:18 +0200 Subject: [PATCH 02/78] chore: removed different quality values --- utils/getImageURL.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 675ffc1c..1ce6e47b 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -142,12 +142,12 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran } } - query.push('fmt=auto') + query.push('fmt=avif') query.push('qlt=default') - query.push('fmt.jpeg.qlt=75') - query.push('fmt.webp.qlt=60') - query.push('fmt.jp2.qlt=40') - query.push('fmt.avif.qlt=60') + // query.push('fmt.jpeg.qlt=75') + // query.push('fmt.webp.qlt=60') + // query.push('fmt.jp2.qlt=40') + // query.push('fmt.avif.qlt=60') if (query.length > 0) { if (url.indexOf('?') > -1) { From 4b72d9cfc147477cb4d6b8cbe82def1c0caedf18 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Mon, 18 Sep 2023 16:01:34 +0100 Subject: [PATCH 03/78] feat: add basic statistics gathering for images --- components/admin/AdminPanel/AdminPanel.tsx | 14 +- .../panels/ImageStatisticsPanel.tsx | 202 ++++++++++++++++++ utils/getImageURL.ts | 2 +- 3 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx diff --git a/components/admin/AdminPanel/AdminPanel.tsx b/components/admin/AdminPanel/AdminPanel.tsx index 462da48e..614b6057 100644 --- a/components/admin/AdminPanel/AdminPanel.tsx +++ b/components/admin/AdminPanel/AdminPanel.tsx @@ -1,7 +1,8 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import Image from 'next/image'; import { Theme, Divider, Typography } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ImageIcon from '@mui/icons-material/Image'; import ExtensionIcon from '@mui/icons-material/Extension'; import VisibilityIcon from '@mui/icons-material/Visibility'; import Accordion from '@mui/material/Accordion'; @@ -14,6 +15,7 @@ import ComponentsPanel from './panels/ComponentsPanel'; import ContentPreviewPanel from './panels/ContentPreviewPanel'; import { getHubName } from '@lib/config/locator/config-locator'; import { useECommerce } from '@components/core/Masthead/ECommerceContext'; +import ImageStatisticsPanel from './panels/ImageStatisticsPanel'; const styles = (theme: Theme) => ({ root: { @@ -78,6 +80,16 @@ const AdminPanel: React.FunctionComponent = (props) => { + + + } aria-controls="panel1a-content"> + + {'Image Statistics'} + + + + + ); diff --git a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx new file mode 100644 index 00000000..55446157 --- /dev/null +++ b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx @@ -0,0 +1,202 @@ +import React, { FC, useState } from 'react'; +import { Button, Chip, CircularProgress, Divider, LinearProgress, Theme, Typography } from '@mui/material'; +import { withStyles, WithStyles } from '@mui/styles' + +interface ImageStatistics { + src: string; + name: string; + types: { [key: string]: string } + sizes: { [key: string]: number } + completed: number, + total: number +} + +const formatTests = ['auto', 'webp', 'jpeg', 'png', 'avif']; + +const expectedTypes: { [key: string]: string } = { + webp: 'image/webp', + jpeg: 'image/jpeg', + png: 'image/png', + avif: 'image/avif' +}; + +async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) { + const images = Array.from(document.images); + + const result: ImageStatistics[] = []; + + const promises: Promise[] = []; + + for (const image of images) { + const src = image.currentSrc; + try { + const url = new URL(src); + + const isAmplienceRequest = url.pathname.startsWith('/i/'); + const accountName = url.pathname.split('/')[2]; + + if (isAmplienceRequest) { + const imageResult: ImageStatistics = { + src, + name: url.pathname.split('/')[3], + types: {}, + sizes: {}, + completed: 0, + total: formatTests.length + } + + result.push(imageResult); + + onChange(result); + + const formatPromises = formatTests.map(async format => { + url.searchParams.set('fmt', format); + + const src = url.toString(); + + try { + const response = await fetch(src); + + const size = Number(response.headers.get("content-length")); + + imageResult.sizes[format] = size; + imageResult.types[format] = response.headers.get("content-type") ?? ''; + imageResult.completed++; + + onChange(result); + } catch (e) { + console.log(`Could not scan image ${image.currentSrc}`); + } + }); + + promises.push(...formatPromises); + } + } catch (e) { + console.log(`Not a valid URL ${image.currentSrc}`); + } + } + + onChange(result); + + await Promise.all(promises); + + return result; +} + +function getProgress(stats: ImageStatistics[]): number { + let completed = 0; + let total = 0; + + for (const stat of stats) { + completed += stat.completed; + total += stat.total; + } + + return 100 * (completed / total); +} + +function getMaxSize(stat: ImageStatistics): number { + let maxSize = 0; + + for (const key of Object.keys(stat.sizes)) { + maxSize = Math.max(maxSize, stat.sizes[key]); + } + + return maxSize; +} + +function isLowest(stat: ImageStatistics, key: string): boolean { + let minSize = stat.sizes[key]; + + for (const key of Object.keys(stat.sizes)) { + if (stat.sizes[key] < minSize) { + return false; + } + } + + return true; +} + +function isValid(stat: ImageStatistics, key: string): boolean { + let type = stat.types[key]; + + return key === 'auto' || type === expectedTypes[key]; +} + +const styles = (theme: Theme) => ({ + root: { + width: '100%' + }, + formControl: { + marginBottom: 10 + }, + input: { + }, + progress: { + } +}); + +interface Props extends WithStyles { + className?: string; + style?: React.CSSProperties +} + +const ImageStatisticsPanel: FC = (props) => { + const { + classes, + ...other + } = props; + + const [calculating, setCalculating] = useState(false); + const [result, setResult] = useState([]); + + const startCalculating = async () => { + setCalculating(true); + await DetermineImageSizes((result) => { setResult([ ...result ]) }); + setCalculating(false); + } + + return (<> +
+ + { + result.length > 0 && <> + + {result.length} Amplience Images detected. + + + { + result.map(stat => { + const maxSize = getMaxSize(stat); + + return <> + + + {stat.name} + + {Object.keys(stat.sizes).map(key => { + const size = stat.sizes[key]; + const pctMax = (size / maxSize); + const lowest = isLowest(stat, key); + const valid = isValid(stat, key); + + return + })} + + }) + } + + } + + ); +}; + +export default withStyles(styles)(ImageStatisticsPanel); \ No newline at end of file diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 1ce6e47b..d754e190 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -142,7 +142,7 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran } } - query.push('fmt=avif') + query.push('fmt=webp') query.push('qlt=default') // query.push('fmt.jpeg.qlt=75') // query.push('fmt.webp.qlt=60') From 497d8665e46f067cde8778c48e66037b1749ea4c Mon Sep 17 00:00:00 2001 From: rs-amp Date: Mon, 18 Sep 2023 16:11:39 +0100 Subject: [PATCH 04/78] feat: sort formats --- components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx index 55446157..9ddf3887 100644 --- a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx +++ b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx @@ -176,7 +176,7 @@ const ImageStatisticsPanel: FC = (props) => { {stat.name} - {Object.keys(stat.sizes).map(key => { + {Object.keys(stat.sizes).sort().map(key => { const size = stat.sizes[key]; const pctMax = (size / maxSize); const lowest = isLowest(stat, key); From 12f561a7f257d383c682d5ee9163ab0355ed6265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 09:27:01 +0200 Subject: [PATCH 05/78] chore: default format --- utils/getImageURL.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index d754e190..1fa6c46b 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -9,6 +9,7 @@ export enum ImageFormat { JPEG = 'jpeg', PNG = 'png', GIF = 'gif', + AVIF = 'avif', DEFAULT = 'default' } @@ -68,7 +69,7 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran const { seoFileName, - format, + format = ImageFormat.DEFAULT, width, height, poi, @@ -142,12 +143,8 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran } } - query.push('fmt=webp') + query.push(`fmt=${format}`) query.push('qlt=default') - // query.push('fmt.jpeg.qlt=75') - // query.push('fmt.webp.qlt=60') - // query.push('fmt.jp2.qlt=40') - // query.push('fmt.avif.qlt=60') if (query.length > 0) { if (url.indexOf('?') > -1) { From c4f80eca728be231e72644539a728ef158123a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 09:28:49 +0200 Subject: [PATCH 06/78] chore: default format for images set to AVIF --- utils/getImageURL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 1fa6c46b..b3f10994 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -69,7 +69,7 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran const { seoFileName, - format = ImageFormat.DEFAULT, + format = ImageFormat.AVIF, width, height, poi, From 1bb1c6105ca1bf509088f1e24987b04b61fb52f8 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Tue, 19 Sep 2023 10:51:03 +0100 Subject: [PATCH 07/78] fix: calculate size from arraybuffer when header is not available --- .../modals/ImageStatisticsModal.tsx | 30 +++++++++++++++++++ .../panels/ImageStatisticsPanel.tsx | 26 ++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 components/admin/AdminPanel/modals/ImageStatisticsModal.tsx diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx new file mode 100644 index 00000000..1b4b2c6c --- /dev/null +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -0,0 +1,30 @@ +import React, { FC, useState } from 'react' +import { useUI } from '../../../ui/UIContext'; +import { ImageStatistics } from '../panels/ImageStatisticsPanel'; +import { Button } from '@mui/material'; + +interface Props { + stats: ImageStatistics[]; +} + +const ImageStatisticsModal: FC = ({stats}) => { + const { closeModal } = useUI(); + + const handleHide = () => { + closeModal(); + }; + + return ( + <> +

Image Statistics

+
+ +
+ + + ); +} + +export default ImageStatisticsModal; \ No newline at end of file diff --git a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx index 9ddf3887..93c0bffd 100644 --- a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx +++ b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx @@ -1,8 +1,10 @@ import React, { FC, useState } from 'react'; import { Button, Chip, CircularProgress, Divider, LinearProgress, Theme, Typography } from '@mui/material'; import { withStyles, WithStyles } from '@mui/styles' +import ImageStatisticsModal from '../modals/ImageStatisticsModal'; +import Modal from '@components/ui/Modal'; -interface ImageStatistics { +export interface ImageStatistics { src: string; name: string; types: { [key: string]: string } @@ -57,7 +59,8 @@ async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) try { const response = await fetch(src); - const size = Number(response.headers.get("content-length")); + const headLength = response.headers.get("content-length"); + const size = headLength ? Number(headLength) : (await response.arrayBuffer()).byteLength; imageResult.sizes[format] = size; imageResult.types[format] = response.headers.get("content-type") ?? ''; @@ -148,8 +151,17 @@ const ImageStatisticsPanel: FC = (props) => { } = props; const [calculating, setCalculating] = useState(false); + const [modalOpen, setModalOpen] = useState(false); const [result, setResult] = useState([]); + const closeModal = () => { + setModalOpen(false); + } + + const openModal = () => { + setModalOpen(true); + } + const startCalculating = async () => { setCalculating(true); await DetermineImageSizes((result) => { setResult([ ...result ]) }); @@ -161,6 +173,16 @@ const ImageStatisticsPanel: FC = (props) => { + + {modalOpen && } + + { + false && !calculating && result.length > 0 && <> + + + } { result.length > 0 && <> From 325963ee960e0657094e68fc264a912f3f7ba718 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Tue, 19 Sep 2023 13:51:43 +0100 Subject: [PATCH 08/78] feat: add simple summary bar graph --- .../admin/AdminPanel/ImageStatisticsGraph.tsx | 117 ++++++++++++++++++ .../modals/ImageStatisticsModal.tsx | 107 ++++++++++++---- .../panels/ImageStatisticsPanel.tsx | 85 ++----------- 3 files changed, 212 insertions(+), 97 deletions(-) create mode 100644 components/admin/AdminPanel/ImageStatisticsGraph.tsx diff --git a/components/admin/AdminPanel/ImageStatisticsGraph.tsx b/components/admin/AdminPanel/ImageStatisticsGraph.tsx new file mode 100644 index 00000000..654e2119 --- /dev/null +++ b/components/admin/AdminPanel/ImageStatisticsGraph.tsx @@ -0,0 +1,117 @@ +import React, { FC, useState } from 'react' +import { useUI } from '../../ui/UIContext'; +import { ImageStatistics } from './panels/ImageStatisticsPanel'; +import { Button, Theme } from '@mui/material'; +import { WithStyles, withStyles } from '@mui/styles'; + +const styles = (theme: Theme) => ({ + table: { + width: '100%', + margin: '12px 0px' + }, + formatHead: { + width: '0' + }, + weightHead: { + textAlign: 'center' + }, + format: { + textAlign: 'end', + verticalAlign: 'middle', + borderRight: '1px solid gray', + paddingRight: '4px' + }, + barWinner: { + backgroundColor: '#65CC02', + padding: '4px 0px' + }, + barLoser: { + backgroundColor: '#8F9496', + padding: '4px 0px' + } +}); + +interface Props extends WithStyles { + stats: ImageStatistics[]; +} + +function getAllFormats(stats: ImageStatistics[]) { + const obj: { [key: string]: boolean } = {}; + + for (const stat of stats) { + const keys = Object.keys(stat.sizes); + for (const key of keys) { + obj[key] = true; + } + } + + return Object.keys(obj).sort(); +} + +function getMaxSize(stats: ImageStatistics[]) { + const sizes: { [key: string]: number } = {}; + let maxSize = 0; + + for (const stat of stats) { + const keys = Object.keys(stat.sizes); + for (const key of keys) { + sizes[key] = (sizes[key] ?? 0) + stat.sizes[key]; + + maxSize = Math.max(maxSize, sizes[key]); + } + } + + return maxSize; +} + +function sumSizes(stats: ImageStatistics[], format: string) { + let size = 0; + + for (const stat of stats) { + size += stat.sizes[format] ?? 0; + } + + return size; +} + +function getMinSize(stats: ImageStatistics[]): number { + const sizes: { [key: string]: number } = {}; + + for (const stat of stats) { + const keys = Object.keys(stat.sizes); + for (const key of keys) { + sizes[key] = (sizes[key] ?? 0) + stat.sizes[key]; + } + } + + let minSize = Infinity; + for (const key of Object.keys(sizes)) { + if (sizes[key] < minSize) { + minSize = sizes[key]; + } + } + + return minSize; +} + +const ImageStatisticsGraph: FC = ({stats, classes}) => { + const formats = getAllFormats(stats); + const maxSize = getMaxSize(stats); + const minSize = getMinSize(stats); + + return + + + + + {formats.map(format => { + const size = sumSizes(stats, format); + return + + + + })} +
Image Weight (bytes)
{format}
{size}
+} + +export default withStyles(styles)(ImageStatisticsGraph); diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 1b4b2c6c..f41ef37c 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,30 +1,87 @@ -import React, { FC, useState } from 'react' -import { useUI } from '../../../ui/UIContext'; -import { ImageStatistics } from '../panels/ImageStatisticsPanel'; -import { Button } from '@mui/material'; +import React, { FC, useState } from "react"; +import { useUI } from "../../../ui/UIContext"; +import { ImageStatistics } from "../panels/ImageStatisticsPanel"; +import { Button, Chip, Divider, Typography } from "@mui/material"; -interface Props { - stats: ImageStatistics[]; +const expectedTypes: { [key: string]: string } = { + webp: 'image/webp', + jpeg: 'image/jpeg', + png: 'image/png', + avif: 'image/avif' +}; + +function getMaxSize(stat: ImageStatistics): number { + let maxSize = 0; + + for (const key of Object.keys(stat.sizes)) { + maxSize = Math.max(maxSize, stat.sizes[key]); + } + + return maxSize; } -const ImageStatisticsModal: FC = ({stats}) => { - const { closeModal } = useUI(); - - const handleHide = () => { - closeModal(); - }; - - return ( - <> -

Image Statistics

-
- -
- - - ); +function isLowest(stat: ImageStatistics, key: string): boolean { + let minSize = stat.sizes[key]; + + for (const key of Object.keys(stat.sizes)) { + if (stat.sizes[key] < minSize) { + return false; + } + } + + return true; } -export default ImageStatisticsModal; \ No newline at end of file +function isValid(stat: ImageStatistics, key: string): boolean { + let type = stat.types[key]; + + return key === 'auto' || type === expectedTypes[key]; +} + +interface Props { + stats: ImageStatistics[]; + onClose: () => void; +} + +const ImageStatisticsModal: FC = ({ stats, onClose }) => { + return ( + <> +

Image Statistics

+
+ {stats.map((stat) => { + const maxSize = getMaxSize(stat); + + return ( + <> + + {stat.name} + {Object.keys(stat.sizes) + .sort() + .map((key) => { + const size = stat.sizes[key]; + const pctMax = size / maxSize; + const lowest = isLowest(stat, key); + const valid = isValid(stat, key); + + return ( + + ); + })} + + ); + })} +
+ + + ); +}; + +export default ImageStatisticsModal; diff --git a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx index 93c0bffd..8b5fbe2d 100644 --- a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx +++ b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx @@ -3,6 +3,7 @@ import { Button, Chip, CircularProgress, Divider, LinearProgress, Theme, Typogra import { withStyles, WithStyles } from '@mui/styles' import ImageStatisticsModal from '../modals/ImageStatisticsModal'; import Modal from '@components/ui/Modal'; +import ImageStatisticsGraph from '../ImageStatisticsGraph'; export interface ImageStatistics { src: string; @@ -13,14 +14,7 @@ export interface ImageStatistics { total: number } -const formatTests = ['auto', 'webp', 'jpeg', 'png', 'avif']; - -const expectedTypes: { [key: string]: string } = { - webp: 'image/webp', - jpeg: 'image/jpeg', - png: 'image/png', - avif: 'image/avif' -}; +const formatTests = ['auto', 'webp', 'jpeg', 'avif']; // png deliberately excluded async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) { const images = Array.from(document.images); @@ -98,40 +92,12 @@ function getProgress(stats: ImageStatistics[]): number { return 100 * (completed / total); } -function getMaxSize(stat: ImageStatistics): number { - let maxSize = 0; - - for (const key of Object.keys(stat.sizes)) { - maxSize = Math.max(maxSize, stat.sizes[key]); - } - - return maxSize; -} - -function isLowest(stat: ImageStatistics, key: string): boolean { - let minSize = stat.sizes[key]; - - for (const key of Object.keys(stat.sizes)) { - if (stat.sizes[key] < minSize) { - return false; - } - } - - return true; -} - -function isValid(stat: ImageStatistics, key: string): boolean { - let type = stat.types[key]; - - return key === 'auto' || type === expectedTypes[key]; -} - const styles = (theme: Theme) => ({ root: { - width: '100%' + width: '100%' }, - formControl: { - marginBottom: 10 + button: { + marginBottom: 6 }, input: { }, @@ -170,50 +136,25 @@ const ImageStatisticsPanel: FC = (props) => { return (<>
- - {modalOpen && } + {modalOpen && } - { - false && !calculating && result.length > 0 && <> - - - } { result.length > 0 && <> {result.length} Amplience Images detected. + { - result.map(stat => { - const maxSize = getMaxSize(stat); - - return <> - - - {stat.name} - - {Object.keys(stat.sizes).sort().map(key => { - const size = stat.sizes[key]; - const pctMax = (size / maxSize); - const lowest = isLowest(stat, key); - const valid = isValid(stat, key); - - return - })} - - }) + !calculating && result.length > 0 && <> + + } } From 5a402fecfc511dfd6724751537fd25ffb0049e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 15:20:44 +0200 Subject: [PATCH 09/78] feat: added accelerated media switch --- components/admin/AdminPanel/AdminPanel.tsx | 8 +- .../admin/AdminPanel/ImageStatisticsGraph.tsx | 2 +- .../modals/ImageStatisticsModal.tsx | 4 +- .../panels/AcceleratedMediaPanel.tsx | 211 ++++++++++++++++++ .../panels/ImageStatisticsPanel.tsx | 165 -------------- 5 files changed, 218 insertions(+), 172 deletions(-) create mode 100644 components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx delete mode 100644 components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx diff --git a/components/admin/AdminPanel/AdminPanel.tsx b/components/admin/AdminPanel/AdminPanel.tsx index 614b6057..7742bf1e 100644 --- a/components/admin/AdminPanel/AdminPanel.tsx +++ b/components/admin/AdminPanel/AdminPanel.tsx @@ -15,7 +15,7 @@ import ComponentsPanel from './panels/ComponentsPanel'; import ContentPreviewPanel from './panels/ContentPreviewPanel'; import { getHubName } from '@lib/config/locator/config-locator'; import { useECommerce } from '@components/core/Masthead/ECommerceContext'; -import ImageStatisticsPanel from './panels/ImageStatisticsPanel'; +import AcceleratedMediaPanel from './panels/AcceleratedMediaPanel'; const styles = (theme: Theme) => ({ root: { @@ -81,13 +81,13 @@ const AdminPanel: React.FunctionComponent = (props) => { - + } aria-controls="panel1a-content"> - {'Image Statistics'} + {'Accelerated Media'} - + diff --git a/components/admin/AdminPanel/ImageStatisticsGraph.tsx b/components/admin/AdminPanel/ImageStatisticsGraph.tsx index 654e2119..db260813 100644 --- a/components/admin/AdminPanel/ImageStatisticsGraph.tsx +++ b/components/admin/AdminPanel/ImageStatisticsGraph.tsx @@ -1,6 +1,6 @@ import React, { FC, useState } from 'react' import { useUI } from '../../ui/UIContext'; -import { ImageStatistics } from './panels/ImageStatisticsPanel'; +import { ImageStatistics } from './panels/AcceleratedMediaPanel'; import { Button, Theme } from '@mui/material'; import { WithStyles, withStyles } from '@mui/styles'; diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index f41ef37c..b66776db 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,6 +1,6 @@ import React, { FC, useState } from "react"; import { useUI } from "../../../ui/UIContext"; -import { ImageStatistics } from "../panels/ImageStatisticsPanel"; +import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; import { Button, Chip, Divider, Typography } from "@mui/material"; const expectedTypes: { [key: string]: string } = { @@ -77,7 +77,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { ); })} - diff --git a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx new file mode 100644 index 00000000..dc3bd705 --- /dev/null +++ b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx @@ -0,0 +1,211 @@ +import React, { FC, useState } from 'react'; +import { Button, Chip, CircularProgress, Divider, IconButton, LinearProgress, Theme, Typography } from '@mui/material'; +import { withStyles, WithStyles } from '@mui/styles' +import ImageStatisticsModal from '../modals/ImageStatisticsModal'; +import Modal from '@components/ui/Modal'; +import ImageStatisticsGraph from '../ImageStatisticsGraph'; + +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import { useDebug } from '@components/ui'; + +export interface ImageStatistics { + src: string; + name: string; + types: { [key: string]: string } + sizes: { [key: string]: number } + completed: number, + total: number +} + +const formatTests = ['auto', 'webp', 'jpeg', 'avif']; // png deliberately excluded + +async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) { + const images = Array.from(document.images); + + const result: ImageStatistics[] = []; + + const promises: Promise[] = []; + + for (const image of images) { + const src = image.currentSrc; + try { + const url = new URL(src); + + const isAmplienceRequest = url.pathname.startsWith('/i/'); + const accountName = url.pathname.split('/')[2]; + + if (isAmplienceRequest) { + const imageResult: ImageStatistics = { + src, + name: url.pathname.split('/')[3], + types: {}, + sizes: {}, + completed: 0, + total: formatTests.length + } + + result.push(imageResult); + + onChange(result); + + const formatPromises = formatTests.map(async format => { + url.searchParams.set('fmt', format); + + const src = url.toString(); + + try { + const response = await fetch(src); + + const headLength = response.headers.get("content-length"); + const size = headLength ? Number(headLength) : (await response.arrayBuffer()).byteLength; + + imageResult.sizes[format] = size; + imageResult.types[format] = response.headers.get("content-type") ?? ''; + imageResult.completed++; + + onChange(result); + } catch (e) { + console.log(`Could not scan image ${image.currentSrc}`); + } + }); + + promises.push(...formatPromises); + } + } catch (e) { + console.log(`Not a valid URL ${image.currentSrc}`); + } + } + + onChange(result); + + await Promise.all(promises); + + return result; +} + +function getProgress(stats: ImageStatistics[]): number { + let completed = 0; + let total = 0; + + for (const stat of stats) { + completed += stat.completed; + total += stat.total; + } + + return 100 * (completed / total); +} + +const VisibilityToggle = ({ selected, onClick }: any) => { + return + {selected && } + {!selected && } + +} + +const styles = (theme: Theme) => ({ + root: { + width: '100%' + }, + button: { + marginTop: 12, + marginBottom: 12 + }, + input: { + }, + progress: { + }, + table: { + width: '100%' + } +}); + +interface Props extends WithStyles { + className?: string; + style?: React.CSSProperties +} + +const AcceleratedMediaPanel: FC = (props) => { + const { + classes, + ...other + } = props; + + const [calculating, setCalculating] = useState(false); + const [modalOpen, setModalOpen] = useState(false); + const [result, setResult] = useState([]); + + const closeModal = () => { + setModalOpen(false); + } + + const openModal = () => { + setModalOpen(true); + } + + const startCalculating = async () => { + setCalculating(true); + await DetermineImageSizes((result) => { setResult([...result]) }); + setCalculating(false); + } + + const { + showContent, + setShowContent, + } = useDebug(); + + const toggleContent = () => { + setShowContent(!showContent); + } + + return (<> + + + + Configuration + + + + + + Enable Accelerated Media + + + + + +
+ + + + {modalOpen && } + + { + result.length > 0 && <> + + {result.length} Amplience Images detected. + + + + { + !calculating && result.length > 0 && <> + + + } + + } + + ); +}; + +export default withStyles(styles)(AcceleratedMediaPanel); \ No newline at end of file diff --git a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx b/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx deleted file mode 100644 index 8b5fbe2d..00000000 --- a/components/admin/AdminPanel/panels/ImageStatisticsPanel.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import React, { FC, useState } from 'react'; -import { Button, Chip, CircularProgress, Divider, LinearProgress, Theme, Typography } from '@mui/material'; -import { withStyles, WithStyles } from '@mui/styles' -import ImageStatisticsModal from '../modals/ImageStatisticsModal'; -import Modal from '@components/ui/Modal'; -import ImageStatisticsGraph from '../ImageStatisticsGraph'; - -export interface ImageStatistics { - src: string; - name: string; - types: { [key: string]: string } - sizes: { [key: string]: number } - completed: number, - total: number -} - -const formatTests = ['auto', 'webp', 'jpeg', 'avif']; // png deliberately excluded - -async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) { - const images = Array.from(document.images); - - const result: ImageStatistics[] = []; - - const promises: Promise[] = []; - - for (const image of images) { - const src = image.currentSrc; - try { - const url = new URL(src); - - const isAmplienceRequest = url.pathname.startsWith('/i/'); - const accountName = url.pathname.split('/')[2]; - - if (isAmplienceRequest) { - const imageResult: ImageStatistics = { - src, - name: url.pathname.split('/')[3], - types: {}, - sizes: {}, - completed: 0, - total: formatTests.length - } - - result.push(imageResult); - - onChange(result); - - const formatPromises = formatTests.map(async format => { - url.searchParams.set('fmt', format); - - const src = url.toString(); - - try { - const response = await fetch(src); - - const headLength = response.headers.get("content-length"); - const size = headLength ? Number(headLength) : (await response.arrayBuffer()).byteLength; - - imageResult.sizes[format] = size; - imageResult.types[format] = response.headers.get("content-type") ?? ''; - imageResult.completed++; - - onChange(result); - } catch (e) { - console.log(`Could not scan image ${image.currentSrc}`); - } - }); - - promises.push(...formatPromises); - } - } catch (e) { - console.log(`Not a valid URL ${image.currentSrc}`); - } - } - - onChange(result); - - await Promise.all(promises); - - return result; -} - -function getProgress(stats: ImageStatistics[]): number { - let completed = 0; - let total = 0; - - for (const stat of stats) { - completed += stat.completed; - total += stat.total; - } - - return 100 * (completed / total); -} - -const styles = (theme: Theme) => ({ - root: { - width: '100%' - }, - button: { - marginBottom: 6 - }, - input: { - }, - progress: { - } -}); - -interface Props extends WithStyles { - className?: string; - style?: React.CSSProperties -} - -const ImageStatisticsPanel: FC = (props) => { - const { - classes, - ...other - } = props; - - const [calculating, setCalculating] = useState(false); - const [modalOpen, setModalOpen] = useState(false); - const [result, setResult] = useState([]); - - const closeModal = () => { - setModalOpen(false); - } - - const openModal = () => { - setModalOpen(true); - } - - const startCalculating = async () => { - setCalculating(true); - await DetermineImageSizes((result) => { setResult([ ...result ]) }); - setCalculating(false); - } - - return (<> -
- - - {modalOpen && } - - { - result.length > 0 && <> - - {result.length} Amplience Images detected. - - - - { - !calculating && result.length > 0 && <> - - - } - - } - - ); -}; - -export default withStyles(styles)(ImageStatisticsPanel); \ No newline at end of file From 8fb7f547a1943f3f2cb12a4cf499ac355cbcd3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 15:29:26 +0200 Subject: [PATCH 10/78] feat: accelerated media context --- .../AdminPanel/AcceleratedMediaContext.tsx | 24 +++++++++++++++++++ .../panels/AcceleratedMediaPanel.tsx | 14 +++++------ pages/_app.tsx | 17 +++++++------ 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 components/admin/AdminPanel/AcceleratedMediaContext.tsx diff --git a/components/admin/AdminPanel/AcceleratedMediaContext.tsx b/components/admin/AdminPanel/AcceleratedMediaContext.tsx new file mode 100644 index 00000000..7fc4df26 --- /dev/null +++ b/components/admin/AdminPanel/AcceleratedMediaContext.tsx @@ -0,0 +1,24 @@ +import React, { createContext, useContext, FC, useState } from "react"; + +export type AcceleratedMediaState = { + acceleratedMedia: boolean; + setAcceleratedMedia: (acceleratedMedia: boolean) => void; +} + + +const Context = createContext<(AcceleratedMediaState)| null>(null); + +export function useAcceleratedMedia(): AcceleratedMediaState { + return useContext(Context) as AcceleratedMediaState; +} + +export const WithAcceleratedMediaState: FC = ({children}) => { + const [acceleratedMedia, setAcceleratedMedia] = useState(true) + + return + {children} + +} \ No newline at end of file diff --git a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx index dc3bd705..0aacb884 100644 --- a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx +++ b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx @@ -13,7 +13,7 @@ import TableRow from '@mui/material/TableRow'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; -import { useDebug } from '@components/ui'; +import { useAcceleratedMedia } from '../AcceleratedMediaContext'; export interface ImageStatistics { src: string; @@ -156,12 +156,12 @@ const AcceleratedMediaPanel: FC = (props) => { } const { - showContent, - setShowContent, - } = useDebug(); + acceleratedMedia, + setAcceleratedMedia + } = useAcceleratedMedia(); - const toggleContent = () => { - setShowContent(!showContent); + const toggleAcceleratedMedia = () => { + setAcceleratedMedia(!acceleratedMedia); } return (<> @@ -176,7 +176,7 @@ const AcceleratedMediaPanel: FC = (props) => { Enable Accelerated Media - + diff --git a/pages/_app.tsx b/pages/_app.tsx index 37d4da73..f4e6a0b7 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,7 +9,8 @@ import { WithUserContext } from '@lib/user/UserContext' import { WithCmsContext } from '@lib/cms/CmsContext' import { WithAppContext } from '@lib/config/AppContext' import { WithDebugState, WithUI } from '@components/ui' -import { WithWindowContext } from '@components/core/WithWindowContext/WindowContext'; +import { WithAcceleratedMediaState } from '@components/admin/AdminPanel/AcceleratedMediaContext' +import { WithWindowContext } from '@components/core/WithWindowContext/WindowContext' import { configureAnalytics } from '@lib/analytics/configureAnalytics' import WithCart from '@components/cart/CartContext' @@ -58,13 +59,15 @@ export default class MyApp extends NextApp { - + - - - - - + + + + + + + From ada6bf746b9d8fa7b5e997f4908ad3db4d66562a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 15:38:25 +0200 Subject: [PATCH 11/78] feat: swtich triggering image reload --- .../admin/AdminPanel/AcceleratedMediaContext.tsx | 2 +- utils/getImageURL.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/admin/AdminPanel/AcceleratedMediaContext.tsx b/components/admin/AdminPanel/AcceleratedMediaContext.tsx index 7fc4df26..5053c041 100644 --- a/components/admin/AdminPanel/AcceleratedMediaContext.tsx +++ b/components/admin/AdminPanel/AcceleratedMediaContext.tsx @@ -13,7 +13,7 @@ export function useAcceleratedMedia(): AcceleratedMediaState { } export const WithAcceleratedMediaState: FC = ({children}) => { - const [acceleratedMedia, setAcceleratedMedia] = useState(true) + const [acceleratedMedia, setAcceleratedMedia] = useState(false) return { if (host === 'i1.adis.ws') { return 'cdn.media.amplience.net'; @@ -143,7 +152,7 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran } } - query.push(`fmt=${format}`) + query.push(`fmt=${finalFormat}`) query.push('qlt=default') if (query.length > 0) { From 36f5dca7d6a07fc975e0bb1faedd848570718b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 15:40:42 +0200 Subject: [PATCH 12/78] chore: file location change --- .../admin/AdminPanel/{ => context}/AcceleratedMediaContext.tsx | 0 components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx | 2 +- pages/_app.tsx | 2 +- utils/getImageURL.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename components/admin/AdminPanel/{ => context}/AcceleratedMediaContext.tsx (100%) diff --git a/components/admin/AdminPanel/AcceleratedMediaContext.tsx b/components/admin/AdminPanel/context/AcceleratedMediaContext.tsx similarity index 100% rename from components/admin/AdminPanel/AcceleratedMediaContext.tsx rename to components/admin/AdminPanel/context/AcceleratedMediaContext.tsx diff --git a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx index 0aacb884..fbb3c0dc 100644 --- a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx +++ b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx @@ -13,7 +13,7 @@ import TableRow from '@mui/material/TableRow'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; -import { useAcceleratedMedia } from '../AcceleratedMediaContext'; +import { useAcceleratedMedia } from '../context/AcceleratedMediaContext'; export interface ImageStatistics { src: string; diff --git a/pages/_app.tsx b/pages/_app.tsx index f4e6a0b7..a8a5209d 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,7 +9,7 @@ import { WithUserContext } from '@lib/user/UserContext' import { WithCmsContext } from '@lib/cms/CmsContext' import { WithAppContext } from '@lib/config/AppContext' import { WithDebugState, WithUI } from '@components/ui' -import { WithAcceleratedMediaState } from '@components/admin/AdminPanel/AcceleratedMediaContext' +import { WithAcceleratedMediaState } from '@components/admin/AdminPanel/context/AcceleratedMediaContext' import { WithWindowContext } from '@components/core/WithWindowContext/WindowContext' import { configureAnalytics } from '@lib/analytics/configureAnalytics' import WithCart from '@components/cart/CartContext' diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 3be61aaa..0c986ee0 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -1,4 +1,4 @@ -import { useAcceleratedMedia } from "@components/admin/AdminPanel/AcceleratedMediaContext"; +import { useAcceleratedMedia } from "@components/admin/AdminPanel/context/AcceleratedMediaContext"; export type CmsImage = { defaultHost: string; From e82ca9297aadd319c31178839c02ec7c68a8ddb4 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Tue, 19 Sep 2023 14:46:03 +0100 Subject: [PATCH 13/78] fix: fix typescript complaints --- components/admin/AdminPanel/ImageStatisticsGraph.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/admin/AdminPanel/ImageStatisticsGraph.tsx b/components/admin/AdminPanel/ImageStatisticsGraph.tsx index db260813..e5c678a5 100644 --- a/components/admin/AdminPanel/ImageStatisticsGraph.tsx +++ b/components/admin/AdminPanel/ImageStatisticsGraph.tsx @@ -13,10 +13,10 @@ const styles = (theme: Theme) => ({ width: '0' }, weightHead: { - textAlign: 'center' + textAlign: 'center' as 'center' }, format: { - textAlign: 'end', + textAlign: 'end' as 'end', verticalAlign: 'middle', borderRight: '1px solid gray', paddingRight: '4px' From ac6a64e28ede2cdc82f3cb1776ac01e0df02055f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 16:30:57 +0200 Subject: [PATCH 14/78] chore: limiting width to 2000 max --- utils/getImageURL.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 0c986ee0..8c2410c8 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -72,13 +72,13 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran const { seoFileName, format = ImageFormat.DEFAULT, - width, + width = 2000, height, poi, scaleMode, scaleFit, aspectRatio, - upscale, + upscale = false, fliph, flipv, rot, From 3f921b6326b7e47ef64818f5fed8234f93fcc6b8 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Tue, 19 Sep 2023 16:50:52 +0100 Subject: [PATCH 15/78] feat: improve details view --- .../modals/ImageStatisticsModal.tsx | 77 +++++++++++-------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index b66776db..4101102b 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,7 +1,6 @@ import React, { FC, useState } from "react"; -import { useUI } from "../../../ui/UIContext"; import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; -import { Button, Chip, Divider, Typography } from "@mui/material"; +import { Button, Card, CardContent, CardMedia, Chip, Grid } from "@mui/material"; const expectedTypes: { [key: string]: string } = { webp: 'image/webp', @@ -47,39 +46,51 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { return ( <>

Image Statistics

-
- {stats.map((stat) => { - const maxSize = getMaxSize(stat); +

{stats.length} Amplience Images detected.

+
+ + { + stats.map((stat, index) => { + const maxSize = getMaxSize(stat); + + return + + + + {Object.keys(stat.sizes) + .sort() + .map((key) => { + const size = stat.sizes[key]; + const pctMax = size / maxSize; + const lowest = isLowest(stat, key); + const valid = isValid(stat, key); - return ( - <> - - {stat.name} - {Object.keys(stat.sizes) - .sort() - .map((key) => { - const size = stat.sizes[key]; - const pctMax = size / maxSize; - const lowest = isLowest(stat, key); - const valid = isValid(stat, key); - - return ( - - ); - })} - - ); - })} + return ( + + ); + })} + + + + }) + } + +
+
+
- ); }; From 5ed7c5f59f0fec29becea3ca18be60217c8fa384 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Tue, 19 Sep 2023 17:42:01 +0100 Subject: [PATCH 16/78] feat: add stacked bar chart for image statistics --- .../admin/AdminPanel/ImageStatisticsStack.tsx | 77 +++++++++++++++++++ .../modals/ImageStatisticsModal.tsx | 11 ++- 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 components/admin/AdminPanel/ImageStatisticsStack.tsx diff --git a/components/admin/AdminPanel/ImageStatisticsStack.tsx b/components/admin/AdminPanel/ImageStatisticsStack.tsx new file mode 100644 index 00000000..408e7463 --- /dev/null +++ b/components/admin/AdminPanel/ImageStatisticsStack.tsx @@ -0,0 +1,77 @@ +import React, { FC, useState } from 'react' +import { useUI } from '../../ui/UIContext'; +import { ImageStatistics } from './panels/AcceleratedMediaPanel'; +import { Button, Theme, Tooltip } from '@mui/material'; +import { WithStyles, withStyles } from '@mui/styles'; + +const styles = (theme: Theme) => ({ + container: { + width: '100%', + height: '24px', + display: 'flex' + }, + barBase: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: 'white', + height: '24px', + outline: '2px solid white', + overflow: 'hidden', + fontSize: '12px' + } +}); + +const colors: { [key: string]: string } = { + jpeg: '#FFA200', + webp: '#00B6FF', + avif: '#65CC02', + auto: '#8F9496', + png: '#E94420' +} + +interface Props extends WithStyles { + stat: ImageStatistics; +} + +function getOrderedFormats(stat: ImageStatistics): {key: string, size: number, same: string[]}[] { + // Formats ordered by size. + const formatSizes = Object.keys(stat.sizes).map(key => ({key, size: stat.sizes[key], same: [key]})); + + formatSizes.sort((a, b) => a.size - b.size); + + for (let i = 0; i < formatSizes.length; i++) { + for (let j = 0; j < i; j++) { + if (formatSizes[i].size == formatSizes[j].size) { + formatSizes[i].same.push(formatSizes[j].key); + formatSizes[j].same.push(formatSizes[i].key); + } + } + } + + return formatSizes; +} + +const ImageStatisticsStack: FC = ({stat, classes}) => { + const ordered = getOrderedFormats(stat); + const maxSize = ordered[ordered.length - 1].size; + const maxKey = ordered[ordered.length - 1].key; + + return
+ { + ordered.map((elem, index) => { + const size = elem.size; + const lastSize = index === 0 ? 0 : ordered[index - 1].size; + const name = elem.same.join('/'); + + return +
+ {name} +
+
+ }) + } +
+} + +export default withStyles(styles)(ImageStatisticsStack); diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 4101102b..bb1dea9a 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,6 +1,7 @@ import React, { FC, useState } from "react"; import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; -import { Button, Card, CardContent, CardMedia, Chip, Grid } from "@mui/material"; +import { Button, Card, CardContent, CardMedia, Chip, Grid, Typography } from "@mui/material"; +import ImageStatisticsStack from "../ImageStatisticsStack"; const expectedTypes: { [key: string]: string } = { webp: 'image/webp', @@ -61,7 +62,11 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { title="green iguana" /> - {Object.keys(stat.sizes) + + {stat.name} + + + {/**Object.keys(stat.sizes) .sort() .map((key) => { const size = stat.sizes[key]; @@ -78,7 +83,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { variant={lowest ? "filled" : "outlined"} /> ); - })} + }) **/} From 9e9b6dee8c9174b0e1bc21c8403de44ef1e40bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Tue, 19 Sep 2023 23:56:10 +0200 Subject: [PATCH 17/78] chore: styles updates --- components/admin/AdminPanel/ImageStatisticsGraph.tsx | 6 ++++-- .../admin/AdminPanel/panels/AcceleratedMediaPanel.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/admin/AdminPanel/ImageStatisticsGraph.tsx b/components/admin/AdminPanel/ImageStatisticsGraph.tsx index e5c678a5..0f9dab9c 100644 --- a/components/admin/AdminPanel/ImageStatisticsGraph.tsx +++ b/components/admin/AdminPanel/ImageStatisticsGraph.tsx @@ -23,11 +23,13 @@ const styles = (theme: Theme) => ({ }, barWinner: { backgroundColor: '#65CC02', - padding: '4px 0px' + padding: '4px 0px 4px 4px', + color: 'white' }, barLoser: { backgroundColor: '#8F9496', - padding: '4px 0px' + padding: '4px 0px 4px 4px', + color: 'white' } }); diff --git a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx index fbb3c0dc..470dccb7 100644 --- a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx +++ b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx @@ -24,7 +24,7 @@ export interface ImageStatistics { total: number } -const formatTests = ['auto', 'webp', 'jpeg', 'avif']; // png deliberately excluded +const formatTests = ['auto', 'jpeg', 'webp', 'avif']; // png deliberately excluded async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) { const images = Array.from(document.images); From 86bd9d4a1a0f35ffe86c6971a2623395fb18dd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 10:02:20 +0200 Subject: [PATCH 18/78] feat: list view and export as csv package --- .../modals/ImageStatisticsModal.tsx | 208 ++++++++++++++---- package-lock.json | 16 ++ package.json | 2 + utils/getImageURL.ts | 6 + 4 files changed, 186 insertions(+), 46 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index bb1dea9a..16ef8d5a 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,7 +1,13 @@ import React, { FC, useState } from "react"; +import { CSVLink } from "react-csv"; import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; -import { Button, Card, CardContent, CardMedia, Chip, Grid, Typography } from "@mui/material"; +import { Button, Card, CardContent, CardMedia, Chip, Grid, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material"; import ImageStatisticsStack from "../ImageStatisticsStack"; +import { getImageURL } from "@utils/getImageURL"; +import { + ListOutlined, + AppsOutlined +} from '@mui/icons-material' const expectedTypes: { [key: string]: string } = { webp: 'image/webp', @@ -44,59 +50,169 @@ interface Props { } const ImageStatisticsModal: FC = ({ stats, onClose }) => { + const [gridView, setGridView] = useState(true) + + const headers = [ + { label: "First Name", key: "firstName" }, + { label: "Last Name", key: "lastName" }, + { label: "Email", key: "email" }, + { label: "Age", key: "age" } + ]; + + const data = [ + { firstName: "Warren", lastName: "Morrow", email: "sokyt@mailinator.com", age: "36" }, + { firstName: "Gwendolyn", lastName: "Galloway", email: "weciz@mailinator.com", age: "76" }, + { firstName: "Astra", lastName: "Wyatt", email: "quvyn@mailinator.com", age: "57" }, + { firstName: "Jasmine", lastName: "Wong", email: "toxazoc@mailinator.com", age: "42" }, + { firstName: "Brooke", lastName: "Mcconnell", email: "vyry@mailinator.com", age: "56" }, + { firstName: "Christen", lastName: "Haney", email: "pagevolal@mailinator.com", age: "23" }, + { firstName: "Tate", lastName: "Vega", email: "dycubo@mailinator.com", age: "87" }, + { firstName: "Amber", lastName: "Brady", email: "vyconixy@mailinator.com", age: "78" }, + { firstName: "Philip", lastName: "Whitfield", email: "velyfi@mailinator.com", age: "22" }, + { firstName: "Kitra", lastName: "Hammond", email: "fiwiloqu@mailinator.com", age: "35" }, + { firstName: "Charity", lastName: "Mathews", email: "fubigonero@mailinator.com", age: "63" } + ]; + + const csvReport = { + data: data, + headers: headers, + filename: 'demsostore-maccelerated-media-report.csv' + }; + return ( - <> +

Image Statistics

{stats.length} Amplience Images detected.

-
- - { - stats.map((stat, index) => { - const maxSize = getMaxSize(stat); - - return - - - - - {stat.name} - - - {/**Object.keys(stat.sizes) - .sort() - .map((key) => { - const size = stat.sizes[key]; - const pctMax = size / maxSize; - const lowest = isLowest(stat, key); - const valid = isValid(stat, key); + setGridView(!gridView)}> + {gridView && } + {!gridView && } + + {gridView && +
+ + { + stats.map((stat, index) => { + const maxSize = getMaxSize(stat); - return ( - - ); - }) **/} - - - - }) - } - -
-
+ return + + + + + {stat.name} + + + + + + }) + } + +
+ } + {!gridView && +
+ Export to CSV + + + + + Media + + + Name + + { + Object.keys(expectedTypes).map((key: string) => { + return ( + <> + + {key} + + + % of max + + + ) + }) + } + + + + { + stats.map((stat, index) => { + const maxSize = getMaxSize(stat); + return ( + + + {stat.name} + + + {stat.name} + + { + Object.keys(stat.sizes).map((key: string) => { + const size = stat.sizes[key]; + const pctMax = size / maxSize; + const lowest = isLowest(stat, key); + const valid = isValid(stat, key); + return ( + <> + + {stat.sizes[key]} + + + + + + ) + }) + } + + ) + }) + } + +
+
+ } +
- +
); }; diff --git a/package-lock.json b/package-lock.json index 14df814f..82554965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "pure-react-carousel": "^1.27.6", "query-string": "^7.1.1", "react": "^17.0.2", + "react-csv": "^2.2.2", "react-dom": "^17.0.2", "react-image-gallery": "^1.2.7", "react-loading-skeleton": "^3.0.2", @@ -76,6 +77,7 @@ "@types/lodash": "^4.14.168", "@types/node": "^17.0.14", "@types/react": "^17.0.2", + "@types/react-csv": "^1.1.4", "@types/react-image-gallery": "^1.0.4", "@types/uuid": "^8.3.4", "babel-loader": "^8.2.1", @@ -10406,6 +10408,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-csv": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/react-csv/-/react-csv-1.1.4.tgz", + "integrity": "sha512-CibB6IhP61GVtLDPey93RKT95DgrDVRVCU+W/cLQ8gjYtVKXCSgt9UYq0DMjIJgnjo1oB/eNk7vNeSPT7eTN4w==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-image-gallery": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/react-image-gallery/-/react-image-gallery-1.2.0.tgz", @@ -21551,6 +21562,11 @@ "node": ">=0.10.0" } }, + "node_modules/react-csv": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz", + "integrity": "sha512-RG5hOcZKZFigIGE8LxIEV/OgS1vigFQT4EkaHeKgyuCbUAu9Nbd/1RYq++bJcJJ9VOqO/n9TZRADsXNDR4VEpw==" + }, "node_modules/react-docgen": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", diff --git a/package.json b/package.json index 9520354c..a8412e15 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "pure-react-carousel": "^1.27.6", "query-string": "^7.1.1", "react": "^17.0.2", + "react-csv": "^2.2.2", "react-dom": "^17.0.2", "react-image-gallery": "^1.2.7", "react-loading-skeleton": "^3.0.2", @@ -78,6 +79,7 @@ "@types/lodash": "^4.14.168", "@types/node": "^17.0.14", "@types/react": "^17.0.2", + "@types/react-csv": "^1.1.4", "@types/react-image-gallery": "^1.0.4", "@types/uuid": "^8.3.4", "babel-loader": "^8.2.1", diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 8c2410c8..9eb0668f 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -114,6 +114,12 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran const query: string[] = []; + const regex = /[?&]([^=#]+)=([^&#]*)/g; + let match; + while ((match = regex.exec(url))) { + query.push(`${match[1]}=${match[2]}`) + } + const params: any = { 'w': width, 'h': height, From ac16e93e42a60481e18ebcca525d6ac7a3859a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 10:49:08 +0200 Subject: [PATCH 19/78] chore: complete csv data and updated thumbnails --- .../modals/ImageStatisticsModal.tsx | 69 ++++++++++++------- utils/getImageURL.ts | 6 +- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 16ef8d5a..1ab646e3 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -12,7 +12,7 @@ import { const expectedTypes: { [key: string]: string } = { webp: 'image/webp', jpeg: 'image/jpeg', - png: 'image/png', + // png: 'image/png', // exclude png avif: 'image/avif' }; @@ -53,30 +53,53 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { const [gridView, setGridView] = useState(true) const headers = [ - { label: "First Name", key: "firstName" }, - { label: "Last Name", key: "lastName" }, - { label: "Email", key: "email" }, - { label: "Age", key: "age" } + { label: "Name", key: "name" }, + { label: "Source", key: "src" } ]; - - const data = [ - { firstName: "Warren", lastName: "Morrow", email: "sokyt@mailinator.com", age: "36" }, - { firstName: "Gwendolyn", lastName: "Galloway", email: "weciz@mailinator.com", age: "76" }, - { firstName: "Astra", lastName: "Wyatt", email: "quvyn@mailinator.com", age: "57" }, - { firstName: "Jasmine", lastName: "Wong", email: "toxazoc@mailinator.com", age: "42" }, - { firstName: "Brooke", lastName: "Mcconnell", email: "vyry@mailinator.com", age: "56" }, - { firstName: "Christen", lastName: "Haney", email: "pagevolal@mailinator.com", age: "23" }, - { firstName: "Tate", lastName: "Vega", email: "dycubo@mailinator.com", age: "87" }, - { firstName: "Amber", lastName: "Brady", email: "vyconixy@mailinator.com", age: "78" }, - { firstName: "Philip", lastName: "Whitfield", email: "velyfi@mailinator.com", age: "22" }, - { firstName: "Kitra", lastName: "Hammond", email: "fiwiloqu@mailinator.com", age: "35" }, - { firstName: "Charity", lastName: "Mathews", email: "fubigonero@mailinator.com", age: "63" } - ]; - + + Object.keys(expectedTypes).forEach((key: string) => { + headers.push({ + label: key, + key + }) + headers.push({ + label: '% of max', + key: `${key}_pct_of_max` + }) + headers.push({ + label: 'Valid', + key: `${key}_valid` + }) + headers.push({ + label: 'Lowest', + key: `${key}_lowest` + }) + }) + + const data: any = [] + stats.forEach((stat, index) => { + const entry: any = {} + entry['name'] = stat.name + entry['src'] = stat.src + const maxSize = getMaxSize(stat); + Object.keys(stat.sizes).forEach((key: string) => { + const size = stat.sizes[key]; + const pctMax = size / maxSize; + const lowest = isLowest(stat, key); + const valid = isValid(stat, key); + const pct = `${Math.round(pctMax * 1000) / 10}%` + entry[key] = size + entry[`${key}_pct_of_max`] = pct + entry[`${key}_valid`] = valid + entry[`${key}_lowest`] = lowest + }) + data.push(entry) + }) + const csvReport = { data: data, headers: headers, - filename: 'demsostore-maccelerated-media-report.csv' + filename: 'demsostore-accelerated-media-report.csv' }; return ( @@ -88,6 +111,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { {gridView && } {!gridView && } + Export to CSV {gridView &&
@@ -117,7 +141,6 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { } {!gridView &&
- Export to CSV @@ -170,7 +193,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { return ( - {stat.name} + {stat.name} {stat.name} diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 9eb0668f..0e243636 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -67,7 +67,7 @@ export type ImageTransformations = { templates?: string[]; }; -export function getImageURL(image: string | CmsImage, transformations: ImageTransformations = {}): string { +export function getImageURL(image: string | CmsImage, transformations: ImageTransformations = {}, removeAllParams = false): string { const { seoFileName, @@ -112,6 +112,10 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran url += `/${encodeURIComponent(seoFileName)}`; } + if (removeAllParams && url.indexOf('?') > -1) { + url = url.split('?')[0] + } + const query: string[] = []; const regex = /[?&]([^=#]+)=([^&#]*)/g; From 8c08c38361428c3d72669cc976aac7a98d9c4f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 11:08:50 +0200 Subject: [PATCH 20/78] chore: accelerated media enabled and fixed table --- .../admin/AdminPanel/context/AcceleratedMediaContext.tsx | 2 +- .../admin/AdminPanel/modals/ImageStatisticsModal.tsx | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/components/admin/AdminPanel/context/AcceleratedMediaContext.tsx b/components/admin/AdminPanel/context/AcceleratedMediaContext.tsx index 5053c041..7fc4df26 100644 --- a/components/admin/AdminPanel/context/AcceleratedMediaContext.tsx +++ b/components/admin/AdminPanel/context/AcceleratedMediaContext.tsx @@ -13,7 +13,7 @@ export function useAcceleratedMedia(): AcceleratedMediaState { } export const WithAcceleratedMediaState: FC = ({children}) => { - const [acceleratedMedia, setAcceleratedMedia] = useState(false) + const [acceleratedMedia, setAcceleratedMedia] = useState(true) return = ({ stats, onClose }) => { entry['name'] = stat.name entry['src'] = stat.src const maxSize = getMaxSize(stat); - Object.keys(stat.sizes).forEach((key: string) => { + Object.keys(expectedTypes).forEach((key: string) => { const size = stat.sizes[key]; const pctMax = size / maxSize; const lowest = isLowest(stat, key); @@ -103,8 +102,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { }; return ( -
+

Image Statistics

{stats.length} Amplience Images detected.

setGridView(!gridView)}> @@ -199,7 +197,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { {stat.name} { - Object.keys(stat.sizes).map((key: string) => { + Object.keys(expectedTypes).map((key: string) => { const size = stat.sizes[key]; const pctMax = size / maxSize; const lowest = isLowest(stat, key); From 99c3a8e621a62b5520fc0c8be921adaf3b75ac62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 11:26:05 +0200 Subject: [PATCH 21/78] chore: updated z-index for the search box --- styles/components/_search.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/styles/components/_search.scss b/styles/components/_search.scss index db85b7ed..c51e6ba7 100644 --- a/styles/components/_search.scss +++ b/styles/components/_search.scss @@ -10,7 +10,7 @@ border-left: 1px solid $textColor; position: relative; display: block; - z-index: 1201; + z-index: 1000; &__icon { position: absolute; right: 15px; @@ -43,7 +43,7 @@ padding: 0 10px 10px 10px; //top: 30px; right: -10px; - z-index: 1201; + z-index: 1000; display: none; overflow: hidden; From 3ffd83330652cef9fd55624465191d5e8e8614c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 12:00:08 +0200 Subject: [PATCH 22/78] chore: modal style update --- components/admin/AdminPanel/modals/ImageStatisticsModal.tsx | 2 +- styles/_modal.scss | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 65a976dd..289220ff 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -228,7 +228,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {
} -
+
diff --git a/styles/_modal.scss b/styles/_modal.scss index 86868396..af694f7a 100644 --- a/styles/_modal.scss +++ b/styles/_modal.scss @@ -23,7 +23,8 @@ background: white; padding: 32px; margin: 32px; - overflow: scroll; + overflow: auto hidden; + border-radius: 8px; min-width: 500px; max-width: calc(100% - 64px); From ecd3de45eacad119196892c88c0eba93bbfb86c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 12:20:47 +0200 Subject: [PATCH 23/78] feat: using proper buttons for actions --- .../modals/ImageStatisticsModal.tsx | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 289220ff..85943340 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -1,12 +1,13 @@ import React, { FC, useState } from "react"; import { CSVLink } from "react-csv"; import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; -import { Button, Card, CardContent, CardMedia, Chip, Grid, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material"; +import { Box, Button, Card, CardContent, CardMedia, Chip, Grid, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material"; import ImageStatisticsStack from "../ImageStatisticsStack"; import { getImageURL } from "@utils/getImageURL"; import { ListOutlined, - AppsOutlined + AppsOutlined, + FileDownload } from '@mui/icons-material' const expectedTypes: { [key: string]: string } = { @@ -105,11 +106,29 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {

Image Statistics

{stats.length} Amplience Images detected.

- setGridView(!gridView)}> - {gridView && } - {!gridView && } - - Export to CSV + + + + + + {gridView &&
From b27224d3cf4aac44231a9a0745d34f3f11c0383d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 12:23:12 +0200 Subject: [PATCH 24/78] feat: all buttons at the bottom of the modal --- .../modals/ImageStatisticsModal.tsx | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 85943340..3f941a24 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -107,28 +107,6 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {

Image Statistics

{stats.length} Amplience Images detected.

- - - - - {gridView &&
@@ -248,7 +226,31 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {
}
- + + + +
From 8b0972cec56b748f77a9ec9d903b79aaf4a02a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 12:46:44 +0200 Subject: [PATCH 25/78] feat: also get image sets on the front-end --- components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx index 470dccb7..4144a446 100644 --- a/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx +++ b/components/admin/AdminPanel/panels/AcceleratedMediaPanel.tsx @@ -38,7 +38,7 @@ async function DetermineImageSizes(onChange: (stats: ImageStatistics[]) => void) try { const url = new URL(src); - const isAmplienceRequest = url.pathname.startsWith('/i/'); + const isAmplienceRequest = url.pathname.startsWith('/i/') || url.pathname.startsWith('/s/'); const accountName = url.pathname.split('/')[2]; if (isAmplienceRequest) { From 94af1eddb6f7086d5d04748dbe0b13dd7758a42c Mon Sep 17 00:00:00 2001 From: rs-amp Date: Wed, 20 Sep 2023 12:23:56 +0100 Subject: [PATCH 26/78] feat: add bar chart --- .../admin/AdminPanel/ImageStatisticsBars.tsx | 89 +++++++++++++++++++ .../admin/AdminPanel/ImageStatisticsStack.tsx | 5 +- .../modals/ImageStatisticsModal.tsx | 4 +- 3 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 components/admin/AdminPanel/ImageStatisticsBars.tsx diff --git a/components/admin/AdminPanel/ImageStatisticsBars.tsx b/components/admin/AdminPanel/ImageStatisticsBars.tsx new file mode 100644 index 00000000..99554663 --- /dev/null +++ b/components/admin/AdminPanel/ImageStatisticsBars.tsx @@ -0,0 +1,89 @@ +import React, { FC } from 'react' +import { ImageStatistics } from './panels/AcceleratedMediaPanel'; +import { Theme, Tooltip } from '@mui/material'; +import { WithStyles, withStyles } from '@mui/styles'; + +const styles = (theme: Theme) => ({ + container: { + width: '100%', + display: 'flex', + flexDirection: 'column' as 'column' + }, + barBase: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + color: 'white', + height: '20px', + margin: '2px 0', + overflow: 'hidden', + fontSize: '12px', + gap: '5px' + }, + format: { + fontSize: '12px', + marginLeft: '4px' + }, + size: { + fontSize: '12px', + marginRight: '4px', + textOverflow: 'ellipsis', + overflow: 'hidden' + } +}); + +const colors: { [key: string]: string } = { + jpeg: '#FFA200', + webp: '#00B6FF', + avif: '#65CC02', + auto: '#8F9496', + png: '#E94420' +} + +interface Props extends WithStyles { + stat: ImageStatistics; +} + +function getOrderedFormats(stat: ImageStatistics): {key: string, size: number, same: string[], dupe: boolean}[] { + // Formats ordered by size. + const formatSizes = Object.keys(stat.sizes).map(key => ({key, size: stat.sizes[key], same: [key], dupe: false})); + + formatSizes.sort((a, b) => a.size - b.size); + + for (let i = 0; i < formatSizes.length; i++) { + for (let j = 0; j < i; j++) { + if (formatSizes[i].size == formatSizes[j].size) { + formatSizes[i].dupe = true; + formatSizes[i].same.push(formatSizes[j].key); + formatSizes[j].same.push(formatSizes[i].key); + } + } + } + + return formatSizes; +} + +const ImageStatisticsBars: FC = ({stat, classes}) => { + const ordered = getOrderedFormats(stat); + const maxSize = ordered[ordered.length - 1].size; + const maxKey = ordered[ordered.length - 1].key; + ordered.reverse(); + + return
+ { + ordered.filter(elem => !elem.dupe).map((elem, index) => { + const size = elem.size; + const name = elem.same.join('/'); + + return +
+ {name} + {elem.size} +
+
+ }) + } +
+} + +export default withStyles(styles)(ImageStatisticsBars); diff --git a/components/admin/AdminPanel/ImageStatisticsStack.tsx b/components/admin/AdminPanel/ImageStatisticsStack.tsx index 408e7463..24650ee5 100644 --- a/components/admin/AdminPanel/ImageStatisticsStack.tsx +++ b/components/admin/AdminPanel/ImageStatisticsStack.tsx @@ -1,7 +1,6 @@ -import React, { FC, useState } from 'react' -import { useUI } from '../../ui/UIContext'; +import React, { FC } from 'react' import { ImageStatistics } from './panels/AcceleratedMediaPanel'; -import { Button, Theme, Tooltip } from '@mui/material'; +import { Theme, Tooltip } from '@mui/material'; import { WithStyles, withStyles } from '@mui/styles'; const styles = (theme: Theme) => ({ diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 65a976dd..16b072dd 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -2,12 +2,12 @@ import React, { FC, useState } from "react"; import { CSVLink } from "react-csv"; import { ImageStatistics } from "../panels/AcceleratedMediaPanel"; import { Button, Card, CardContent, CardMedia, Chip, Grid, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material"; -import ImageStatisticsStack from "../ImageStatisticsStack"; import { getImageURL } from "@utils/getImageURL"; import { ListOutlined, AppsOutlined } from '@mui/icons-material' +import ImageStatisticsBars from "../ImageStatisticsBars"; const expectedTypes: { [key: string]: string } = { webp: 'image/webp', @@ -128,7 +128,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { {stat.name} - +
From 7894c42e2aaf1a014051e48c99945f736693dd6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 14:15:05 +0200 Subject: [PATCH 27/78] chore: using material ui modal component --- .../modals/ImageStatisticsModal.tsx | 20 ++++++++++++------- .../panels/AcceleratedMediaPanel.tsx | 9 ++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index dbf0f475..6c75b59c 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -104,12 +104,18 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { }; return ( -
-

Image Statistics

-

{stats.length} Amplience Images detected.

- +
+ Image Statistics + {stats.length} Amplience Images detected. {gridView && -
+
{ stats.map((stat, index) => { @@ -136,7 +142,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {
} {!gridView && -
+
@@ -226,7 +232,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {
} -
+
- - {modalOpen && } + + { result.length > 0 && <> From 4fe7a400afc581fca7b5f7acf216495727f3822f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 14:29:40 +0200 Subject: [PATCH 28/78] chore: styling sidebar --- components/admin/AdminPanel/AdminPanel.tsx | 12 +++++++++--- components/ui/Sidebar/Sidebar.tsx | 6 +++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/components/admin/AdminPanel/AdminPanel.tsx b/components/admin/AdminPanel/AdminPanel.tsx index 7742bf1e..e0b60aeb 100644 --- a/components/admin/AdminPanel/AdminPanel.tsx +++ b/components/admin/AdminPanel/AdminPanel.tsx @@ -23,7 +23,12 @@ const styles = (theme: Theme) => ({ logo: { display: 'flex', padding: '10px 10px 4px 10px', - justifyContent: 'left' + justifyContent: 'center' + }, + environment: { + display: 'flex', + justifyContent: 'left', + padding: '8px' }, icon: { marginRight: '0.4rem', @@ -52,11 +57,12 @@ const AdminPanel: React.FunctionComponent = (props) => { amplience
-
+
hub {hubname}
-
+
+
vendor {vendor}
diff --git a/components/ui/Sidebar/Sidebar.tsx b/components/ui/Sidebar/Sidebar.tsx index 0e9f9868..d0ecacdd 100644 --- a/components/ui/Sidebar/Sidebar.tsx +++ b/components/ui/Sidebar/Sidebar.tsx @@ -25,20 +25,20 @@ const styles = (theme: Theme) => ({ }, panel: { position: 'fixed' as 'fixed', - width: 300, + width: 400, bottom: 0, top: 0, zIndex: 1100, transition: 'all 200ms ease-out', }, left: { - left: -300, + left: -400, '&$open': { left: 0 } }, right: { - right: -300, + right: -400, '&$open': { right: 0 } From 4b322494329e539e353aa046ad931e33defd576c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 14:34:41 +0200 Subject: [PATCH 29/78] feat: clickable images and thumbnails --- .../modals/ImageStatisticsModal.tsx | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 6c75b59c..00e9aedb 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -104,13 +104,13 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { }; return ( -
Image Statistics {stats.length} Amplience Images detected. @@ -123,11 +123,13 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { return - + + + {stat.name} @@ -195,7 +197,9 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { return ( - {stat.name} + + {stat.name} + {stat.name} @@ -234,30 +238,30 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { }
- + - + -
From 8377c574d6cbe8e7013dbd318d0783e9db0dc066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 14:38:59 +0200 Subject: [PATCH 30/78] chore: updated accelerated media icon --- components/admin/AdminPanel/AdminPanel.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/admin/AdminPanel/AdminPanel.tsx b/components/admin/AdminPanel/AdminPanel.tsx index e0b60aeb..422ff53a 100644 --- a/components/admin/AdminPanel/AdminPanel.tsx +++ b/components/admin/AdminPanel/AdminPanel.tsx @@ -1,13 +1,13 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import Image from 'next/image'; import { Theme, Divider, Typography } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ImageIcon from '@mui/icons-material/Image'; import ExtensionIcon from '@mui/icons-material/Extension'; import VisibilityIcon from '@mui/icons-material/Visibility'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; +import ElectricBoltIcon from '@mui/icons-material/ElectricBolt'; import { withStyles, WithStyles } from '@mui/styles' import WithAdminTheme from '@components/admin/AdminTheme'; @@ -89,7 +89,7 @@ const AdminPanel: React.FunctionComponent = (props) => { } aria-controls="panel1a-content"> - + {'Accelerated Media'} From f650c40fab628109fde3bfabcfb34bacb3396fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Wed, 20 Sep 2023 15:18:51 +0200 Subject: [PATCH 31/78] feat: modal takes full space --- components/admin/AdminPanel/modals/ImageStatisticsModal.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx index 00e9aedb..9b398b88 100644 --- a/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx +++ b/components/admin/AdminPanel/modals/ImageStatisticsModal.tsx @@ -106,14 +106,17 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => { return (
Image Statistics - {stats.length} Amplience Images detected. + {stats.length} Amplience image{stats.length > 0 && 's'} detected. {gridView &&
@@ -236,6 +239,7 @@ const ImageStatisticsModal: FC = ({ stats, onClose }) => {
} +
From d8ffd0e48484663779a3c6b9e9f72922c4f2e6c6 Mon Sep 17 00:00:00 2001 From: rs-amp Date: Thu, 21 Sep 2023 10:07:44 +0100 Subject: [PATCH 51/78] fix: text wrap on bar chart --- components/admin/AdminPanel/ImageStatisticsBars.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/admin/AdminPanel/ImageStatisticsBars.tsx b/components/admin/AdminPanel/ImageStatisticsBars.tsx index 475ad129..34b12f7a 100644 --- a/components/admin/AdminPanel/ImageStatisticsBars.tsx +++ b/components/admin/AdminPanel/ImageStatisticsBars.tsx @@ -22,7 +22,8 @@ const styles = (theme: Theme) => ({ }, format: { fontSize: '12px', - marginLeft: '4px' + marginLeft: '4px', + whiteSpace: 'nowrap' as 'nowrap' }, size: { fontSize: '12px', From f1d5edb9df54b2eb0c4953a4b2ce8f1c1ca3ec75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 11:22:32 +0200 Subject: [PATCH 52/78] fix: rebuild URL from transformations and existing --- utils/getImageURL.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 9a601b0d..07b5a258 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -112,12 +112,14 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran url += `/${encodeURIComponent(seoFileName)}`; } + // Remove all existing URL parameters if (removeAllParams && url.indexOf('?') > -1) { url = url.split('?')[0] } const query: string[] = []; + // Get parameters from Transformations const params: any = { 'w': width, 'h': height, @@ -135,12 +137,14 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran 'qlt': quality }; + // Re-add existing parameters from URL const regex = /[?&]([^=#]+)=([^&#]*)/g; let match; while ((match = regex.exec(url))) { if (params[match[1]] == undefined || params[match[1]] == null) params[match[1]] = match[2] } + // Add all parameters to query for (let param of Object.keys(params)) { const value = params[param]; if (value !== undefined && value !== null && value != 0) { @@ -162,16 +166,15 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran } } + // Add format and quality query.push(`fmt=${finalFormat}`) query.push('qlt=default') - if (query.length > 0) { - if (url.indexOf('?') > -1) { - url += `&${query.join('&')}`; - } else { - url += `?${query.join('&')}`; - } + // Rebuild URL + if (url.indexOf('?') > -1) { + url = url.split('?')[0] } + url += `?${query.join('&')}`; return url; } \ No newline at end of file From 367a8fb606a4d86e5cb9fddc97f9ec525f014c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 11:23:45 +0200 Subject: [PATCH 53/78] chore: updated width --- components/cms-modern/Image/Image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cms-modern/Image/Image.tsx b/components/cms-modern/Image/Image.tsx index d41a72c2..7f7dafad 100644 --- a/components/cms-modern/Image/Image.tsx +++ b/components/cms-modern/Image/Image.tsx @@ -108,7 +108,7 @@ const Image: FC = ({ {source({ minWidth: '768', width: '1024', highDensityWidth: '2048', poiAspect: '1.5:1' })} {source({ maxWidth: '768', width: '768', highDensityWidth: '1536', poiAspect: '1:1' })} - {imageAltText} + {imageAltText} ); From a9809ed82ec93d710decbbe92d1995b00f503ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 11:28:24 +0200 Subject: [PATCH 54/78] chore: updated templates --- .../banner/templates/acc-template-image.hbs | 10 +++++----- .../image/templates/acc-template-image.hbs | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/styles/dc-accelerators/renders/banner/templates/acc-template-image.hbs b/styles/dc-accelerators/renders/banner/templates/acc-template-image.hbs index 1a6d334f..b1709d6a 100644 --- a/styles/dc-accelerators/renders/banner/templates/acc-template-image.hbs +++ b/styles/dc-accelerators/renders/banner/templates/acc-template-image.hbs @@ -1,6 +1,6 @@ {{#roundelProperties}} @@ -49,24 +49,24 @@ media="(max-width: 768px)"> {{imageAltText}} {{else}} @@ -101,12 +101,12 @@ media="(max-width: 768px)"> {{imageAltText}} {{/roundelProperties}} From 37d0ee8bdf7afec6fe4ff3a233438fa21c3f9f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 11:28:58 +0200 Subject: [PATCH 55/78] chore: removed default width --- utils/getImageURL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 07b5a258..ce790946 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -72,7 +72,7 @@ export function getImageURL(image: string | CmsImage, transformations: ImageTran const { seoFileName, format = ImageFormat.DEFAULT, - width = 1500, + width, height, poi, scaleMode, From b0e527eb2bd10da0cf7a736475c6ee631a85c221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 14:15:24 +0200 Subject: [PATCH 56/78] chore: updated sizes for cache reset --- .../CuratedProductGridCard/CuratedProductGridCard.tsx | 4 ++-- components/product/ProductCard/ProductCard.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/cms/CuratedProductGrid/CuratedProductGridCard/CuratedProductGridCard.tsx b/components/cms/CuratedProductGrid/CuratedProductGridCard/CuratedProductGridCard.tsx index 4ca72804..634275d5 100644 --- a/components/cms/CuratedProductGrid/CuratedProductGridCard/CuratedProductGridCard.tsx +++ b/components/cms/CuratedProductGrid/CuratedProductGridCard/CuratedProductGridCard.tsx @@ -84,8 +84,8 @@ const CuratedProductGridCard: React.SFC = (props) => { } let imageUrl = result.overrides?.image - ? getImageURL(result.overrides.image, {width: 540, height: 812}) - : getImageURL(result.variants[0].images[0].url, {width: 540, height: 812}) + ? getImageURL(result.overrides.image, {width: 540, height: 810}) + : getImageURL(result.variants[0].images[0].url, {width: 540, height: 810}) return ( diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 50f63856..af080160 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -111,13 +111,13 @@ const ProductCardSkeleton: React.SFC = (props) => { firstImage = variant.images[0].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if(firstImage.indexOf('cdn.media.amplience.net') > 0){ - firstImage = getImageURL(firstImage, {width: 540, height: 812}, true) + firstImage = getImageURL(firstImage, {width: 540, height: 810}, true) } } if (variant.images[1] && variant.images[1].url){ secondImage = variant.images[1].url.replace("i8.amplience.net", "cdn.media.amplience.net"); if(secondImage.indexOf('cdn.media.amplience.net') > 0){ - secondImage = getImageURL(firstImage, {width: 540, height: 812}, true) + secondImage = getImageURL(firstImage, {width: 540, height: 810}, true) } } } From e88df88dd48e5bba47a4163833ab53f0c8eecf2c Mon Sep 17 00:00:00 2001 From: rs-amp Date: Thu, 21 Sep 2023 14:13:44 +0100 Subject: [PATCH 57/78] feat: add limiter for image size --- components/cms-modern/Image/Image.tsx | 7 +-- utils/getImageURL.ts | 77 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/components/cms-modern/Image/Image.tsx b/components/cms-modern/Image/Image.tsx index d41a72c2..8da32db7 100644 --- a/components/cms-modern/Image/Image.tsx +++ b/components/cms-modern/Image/Image.tsx @@ -103,9 +103,10 @@ const Image: FC = ({ ) : ( - {source({ minWidth: '1280', width: '1500', highDensityWidth: '3000', poiAspect: '2:1' })} - {source({ minWidth: '1024', width: '1280', highDensityWidth: '2560', poiAspect: '2:1' })} - {source({ minWidth: '768', width: '1024', highDensityWidth: '2048', poiAspect: '1.5:1' })} + {/* High density widths selected to be below max avif image size at aspect ratio. (2.5mil pixels) */} + {source({ minWidth: '1280', width: '1500', highDensityWidth: '2234', poiAspect: '2:1' })} + {source({ minWidth: '1024', width: '1280', highDensityWidth: '2234', poiAspect: '2:1' })} + {source({ minWidth: '768', width: '1024', highDensityWidth: '1920', poiAspect: '1.5:1' })} {source({ maxWidth: '768', width: '768', highDensityWidth: '1536', poiAspect: '1:1' })} {imageAltText} diff --git a/utils/getImageURL.ts b/utils/getImageURL.ts index 9a601b0d..0e9bf7a7 100644 --- a/utils/getImageURL.ts +++ b/utils/getImageURL.ts @@ -67,7 +67,84 @@ export type ImageTransformations = { templates?: string[]; }; +const avifMaxPixels = 2500000; + +function limitSize(width: number, height: number, maxPixels: number): { width: number, height: number } | undefined { + const pixels = width * height; + + if (pixels <= maxPixels) { + return undefined; + } + + const heightFromWidth = height / width; + + const newWidth = Math.floor(Math.sqrt(maxPixels / heightFromWidth)); + const newHeight = Math.floor(newWidth * heightFromWidth); + + return { + width: newWidth, + height: newHeight + } +} + +function constrainMaxSize(transformations: ImageTransformations, maxPixels: number): ImageTransformations { + // Given a max number of pixels, + // Constrain the size of the image, while also keeping its aspect ratio. + // If it's not possible, leave it untouched. + const aspect = transformations.aspectRatio; + + if (transformations.width == null && transformations.height == null) { + return transformations; + } + + // Both dimensions can be controlled. + if (transformations.width != null && transformations.height != null) { + const newSize = limitSize(transformations.width, transformations.height, maxPixels); + + return (newSize == null) ? transformations : { + ...transformations, + width: newSize.width, + height: newSize.height + }; + } + + // Can only control scale if we know the aspect. + if (aspect == null) { + return transformations; + } + + const aspectSplit = aspect.split(':'); + const widthFromHeight = Number(aspectSplit[0])/Number(aspectSplit[1]); + const heightFromWidth = 1/widthFromHeight; + + if (isNaN(widthFromHeight)) { + return transformations; + } + + if (transformations.width != null) { + // Scale the width to be within the maxPixels. + const newSize = limitSize(transformations.width, transformations.width * heightFromWidth, maxPixels); + + return (newSize == null) ? transformations : { + ...transformations, + width: newSize.width + }; + } else if (transformations.height != null) { + // Height must be defined instead. + const newSize = limitSize(transformations.height * widthFromHeight, transformations.height, maxPixels); + + return (newSize == null) ? transformations : { + ...transformations, + height: newSize.height + }; + } + + // Not really possible to get here, but typescript doesn't know that. + return transformations; +} + export function getImageURL(image: string | CmsImage, transformations: ImageTransformations = {}, removeAllParams = false): string { + transformations = constrainMaxSize(transformations, avifMaxPixels); const { seoFileName, From 8e095e5385b2167428978784e72befbb878984ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 15:33:35 +0200 Subject: [PATCH 58/78] fix: passing format to images --- .../ProductMediaViewer/ProductMediaViewer.tsx | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/components/product/ProductMediaViewer/ProductMediaViewer.tsx b/components/product/ProductMediaViewer/ProductMediaViewer.tsx index 9dccc99b..c9a4c2c3 100644 --- a/components/product/ProductMediaViewer/ProductMediaViewer.tsx +++ b/components/product/ProductMediaViewer/ProductMediaViewer.tsx @@ -5,7 +5,8 @@ import { useProduct } from '../WithProduct/WithProduct'; import ImageGallery from 'react-image-gallery'; import _ from 'lodash' import { withStyles, WithStyles } from '@mui/styles' -import { getImageURL } from '@utils/getImageURL'; +import { ImageFormat, getImageURL } from '@utils/getImageURL'; +import { useAcceleratedMedia } from '@components/admin/AdminPanel/context/AcceleratedMediaContext'; const styles = (theme: Theme) => ({ }); @@ -31,6 +32,13 @@ const ProductMediaViewer: React.FunctionComponent = (props) => { let { cms } = useAppContext() + const { + acceleratedMedia + } = useAcceleratedMedia(); + + let format = 'auto' + if (acceleratedMedia) format = ImageFormat.AVIF + const container = createRef(); useEffect(() => { if (!window || !container.current || !product) { @@ -51,18 +59,18 @@ const ProductMediaViewer: React.FunctionComponent = (props) => { view: variant, secure: true, templates: { - thumb: 'w=85&h=85&qlt=65&unsharp=0,1,1,7', + thumb: `w=85&h=85&unsharp=0,1,1,7&qlt=default&fmt=${format}`, desktop: { - main: 'w=600&qlt=75&upscale=false', - mainRetina: 'w=1200&qlt=75&upscale=false', + main: `w=600&upscale=false&qlt=default&fmt=${format}`, + mainRetina: `w=1200&upscale=false&qlt=default&fmt=${format}`, }, desktopFull: { - main: 'w=1000&upscale=false', - mainRetina: 'w=2000&upscale=false', + main: `w=1000&upscale=false&qlt=default&fmt=${format}`, + mainRetina: `w=2000&upscale=false&qlt=default&fmt=${format}`, }, mobile: { - main: 'w=500&h=500&upscale=false', - mainRetina: 'w=1000&h=1000&upscale=false', + main: `w=500&h=500&upscale=false&qlt=default&fmt=${format}`, + mainRetina: `w=1000&h=1000&upscale=false&qlt=default&fmt=${format}`, }, }, ampConfigs: { From 964baeed94f9351a0d9c95575b4f59f7f947e4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 15:37:43 +0200 Subject: [PATCH 59/78] fix: updated to default quality --- public/js/viewer/viewer.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/viewer/viewer.min.js b/public/js/viewer/viewer.min.js index fb70b4de..c5df6eeb 100644 --- a/public/js/viewer/viewer.min.js +++ b/public/js/viewer/viewer.min.js @@ -11,5 +11,5 @@ deep:!0,timestamp:l(),arg:"'"+c+"'",func:"amp.jsonReturn"}),i=amp.get.createScri }var e=b._canCSS3.transform,f=d.prototype;f.init=function(){var c=this;this.element=b._container[0],this.rotation=0,this.panelCount=b.count,this.totalPanelCount=this.element.children.length,this.theta=0,this.isHorizontal="horz"==b.options.dir,b._container.css("perspective","1000px"),this.modify(),setTimeout(function(){c.animation(!0)},10),b.canTouch&&b.options.gesture.enabled&&b._children.on("touchstart",a.proxy(this.start,this))},f.animation=function(a){a?(b._children.css("transitionTimingFunction",b.options.easing),b._children.css("transitionDuration",b.options.animDuration+"ms")):(b._children.css("transitionTimingFunction",""),b._children.css("transitionDuration",""))},f.start=function(c){if(c.originalEvent&&c.originalEvent.touches&&c.originalEvent.touches[0]&&c.originalEvent.touches.length!=b.options.gesture.fingers)return!0;var c=this.getEvent(c);this.xo=c.pageX-c.target.offsetLeft,this.yo=c.pageY-c.target.offsetTop,this.changed=!1,this.moved=!1,this.animation(!1),this.startPos=this.rotation,a(window).on("touchmove",a.proxy(this.move,this)),a(window).on("touchcancel",a.proxy(this.stop,this)),a(window).on("touchend",a.proxy(this.stop,this))},f.move=function(a){if(a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&a.originalEvent.touches.length!=b.options.gesture.fingers)return!0;this.lastEvent=a,this.moved=!0,a=this.getEvent(a);var c=a.pageX-this.xo,d=this.yo-a.pageY,e="horz"==b.options.dir?c:d;return e=e>0?Math.min(this.theta/2,e/10):Math.max(0-this.theta/2,e/10),this.rotation=this.startPos+e,this.transform(),!1},f.getEvent=function(a){return"touchend"!=a.type&&"touchcancel"!=a.type||(a=this.lastEvent),a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&(a=a.originalEvent.touches[0]),a},f.stop=function(c){if(a(window).off("touchmove",a.proxy(this.move,this)),a(window).off("touchcancel",a.proxy(this.stop,this)),a(window).off("touchend",a.proxy(this.stop,this)),this.animation(!0),this.moved&&!this.changed){c=this.getEvent(c);var d=c.pageX-this.xo,e=this.yo-c.pageY,f="horz"==b.options.dir?d:e;if(this.rotation=this.startPos,Math.abs(f)>=b.options.gesture.distance)if(f<0){if(b.canNext())return void b.next()}else if(b.canPrev())return void b.prev();this.transform(),this.changed=!0}},f.modify=function(){var a,c,d;for(this.xOffset=b._container.width()/2-b._children.eq(0).width()/2,this.yOffset=b._container.height()/2-b._children.eq(0).height()/2,this.panelSize=this.isHorizontal?b._children.eq(0).width():b._children.eq(0).height(),this.rotateFn=this.isHorizontal?"rotateY":"rotateX",this.theta=360/this.panelCount,this.radius=Math.round(this.panelSize/2/Math.tan(Math.PI/this.panelCount)),delete this.styles,delete this.angles,this.styles=[],this.angles=[],d=0;d360;)b-=360;for(;b<0;)b+=360;var c;c=b<=180?180-b:b-180,this.element.children[a].style.zIndex=c,this.element.children[a].style[e]="translateZ(-"+this.radius+"px) "+this.rotateFn+"("+this.rotation+"deg)"+this.styles[a]}},f.focus=function(a,c,d){var e=b._direction(a),f=b._loopCount(e,b._index,a),g=b._children.eq(a-1),h=b._children.eq(b._index-1);b._setState(g,"visible"),b._setState(h,"invisible"),e?this.rotation-=this.theta*f:this.rotation+=this.theta*f,this.transform(),d&&d()},f.layout=function(a){this.modify(),this.focus(a)};var g=new d;return g.init(),g};a.amp.ampCarousel.prototype._layoutManagers.carousel3D={requiredFeatures:["can3D","transform"],create:b}}()}(jQuery),function(a){a.widget("amp.ampImage",{options:{errImg:null,preload:"visible",insertAfter:!1},_loadedHistory:[],_getCreateOptions:function(){var b=this.element.data().ampImage;return b?a.extend(!0,{},this.options,b):this.options},_create:function(){this.element.addClass("amp"),this.element.addClass("amp-image");var b=this;this.element.bind("load",function(a){b._loaded()}),this.element.bind("error",function(){b._failLoad()}),a.inArray(this.options.preload,["created","visible","none"])==-1&&(this.options.preload="visible"),"created"==this.options.preload&&this.newLoad(),this._track("created")},dimensionsParams:function(b){var c=this,d=c.element.data("amp-dimensions"),e=b;if(!d)return e;var f=e.indexOf("?")===-1?"?":"&",g="";return a.each(d[0],function(b,d){var h=new RegExp(f+b+"=[0-9]*","g"),i=e.match(h);i&&i.length>0&&a.each(i,function(a,b){e=e.replace(b,"")});var j="window"===d.domName?a(window):c.element.closest(d.domName);g+=f+b+"="+parseFloat(j[d.domProp](),10),f="&"}),e+=g},newLoad:function(){var b=this.element.attr("src")&&""!=this.element.attr("src")?this.element.attr("src"):this.element.attr("data-amp-src");b=this.dimensionsParams(b);var c=this.element.attr("data-amp-srcset")||null;if(a.inArray(b,this._loadedHistory)!==-1)return this.loading&&this.loading.remove(),this.element.attr("src",b),c&&this.element.attr("srcset",c),void this.element.show();this.loading||(this.loading=a('
')),this.element.hide(),this.options.insertAfter?this.options.insertAfter.prepend(this.loading):this.element.parent().append(this.loading),this.element.attr("src",""),this.element.attr("src",b),c&&(this.element.attr("srcset",""),this.element.attr("srcset",c))},visible:function(a){if(a&&a!=this._visible&&"visible"==this.options.preload){if(this.loaded||this.loading)return;this.newLoad()}this._visible=a},load:function(a){this.loaded||this.loading||this.newLoad()},preload:function(){this.element.parent().hasClass("amp-spin")||this.newLoad()},loaded:!1,_loaded:function(){this._loadedHistory.push(this.element.attr("src")),this._track("loaded",!0),this.loaded=!0,this.loading&&this.loading.remove(),this.element.show()},_failLoad:function(){this.options.errImg?this.element.attr("src",this.options.errImg):window.amp&&.conf&&.conf.err_img&&this.element.attr("src",amp.conf.err_img)},_track:function(a,b){this._trigger(a,null,b),window.amp&&.stats&&.stats.event&&.stats.event(this.element,"image",a,b)},_destroy:function(){this.element.removeClass("amp"),this.element.removeClass("amp-image"),this.loading&&this.loading.remove(),this.element.css("display",""),this._removeEmptyAttributeHelper(this.element)},_removeEmptyAttributeHelper:function(a,b){for(var c=b||["class","style"],d=0,e=c.length;d
'),this.parent=this.element.parent(),this.parent.prepend(this.loading),this.element.wrap('
'),this.overflow=this.element.parent(),this.wrapper=a('
'),this.imgs=[];var d=0;do{var e=a('');e.css(b),this.wrapper.append(e),this.imgs.push(e),d++}while(d<(this._cycle&&this._cycle.len));if(this.options.responsive&&this.element.css({height:"auto",width:"100%",maxWidth:"100%"}),this.options.target){this.mark=this.options.map?{name:"map",inner:"inner"}:{name:"box",inner:"wrapper"};try{this[this.mark.name]=a("body").find(this.options.target)}catch(f){this[this.mark.name]=!1}this[this.mark.name]&&this[this.mark.name].length>0?(this.options.lens&&(this.lens=a('
'),"map"==this.mark.name?(this[this.mark.name].addClass("amp-zoom-map"),this[this.mark.inner]=a('
'),this[this.mark.inner].append(a('')),this[this.mark.inner].append(this.lens)):(this[this.mark.name].addClass("amp-zoom-container"),this.parent.append(this.lens))),this[this.mark.inner].hide(),this[this.mark.name].append(this[this.mark.inner]),this[this.mark.inner].addClass(this.options.states.inactive),this[this.mark.inner][0].relatedUUID=this.uuid):this[this.mark.name]=!1}this.box||(this.overflow.append(this.wrapper),this.canHideEl=!!a.amp.ampImage),this.target=this.imgs[0],this._setZoomCursor(this.parent),this.parent.addClass(this.options.states.inactive),("created"==this.options.preload.image||this.element[0].src)&&this._loadImage(),"created"==this.options.preload.zoomed&&this._loadZoomed()},_onImageLoad:function(){if(!this._imageLoaded){this._track("loaded",!0),this._imageLoaded=!0,this._imageLoading=!1,this._originalImage=this._getNaturalSize(this.element[0].src);var b=this;this._calcSize(),this.options.responsive&&a(window).bind("resize",function(a){return function(){return a.zoomed&&a.zoom(!1),a._calcSize()}}(b)),this.moved=!1,this.canTouch=!!("ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),this.zoomBy=1,this.pos={start:{x:0,y:0},last:{x:0,y:0},cur:{x:0,y:0}};var c=function(){var c=function(a){return b.moved=!0,!0},d=function(a){return e(),!0},e=function(f){if(b.pos.cur=b.pos.last,b.mousedown=!1,b.parent.off(b.canTouch?"touchmove":"mousemove",a.proxy(c,b)),b.canTouch||b.parent.off("mouseleave",a.proxy(d,b)),b.parent.off(b.canTouch?"touchend":"mouseup",a.proxy(e,b)),!b.moved)return b.toggle(f)},f=function(f){b.zoomed&&(f.stopPropagation(),f.preventDefault()),b.mousedown=!0;var g=b._getEvent(f);b.pos.start={x:g.pageX,y:g.pageY},setTimeout(function(){b.parent.on(b.canTouch?"touchmove":"mousemove",a.proxy(c,b)),b.parent.on(b.canTouch?"touchend":"mouseup",a.proxy(e,b))},1),b.canTouch||b.parent.on("mouseleave",a.proxy(d,b)),b.moved=!1;f.timeStamp;return b.startTouchEvent=f,!0};b.parent.on(b.canTouch?"touchstart":"mousedown",a.proxy(f,b))};if(this.canTouch){if("disable"==this.options.activate.touch)return!1;if("doubleTap"==this.options.activate.touch){var d=300,e=20;this._lastEvent="";var f=function(c){b.parent.on("touchend touchcancel",a.proxy(g,b)),this.startTouchEvent=c;var c=this._getEvent(c);b.pos.start={x:c.pageX,y:c.pageY},c.timeStamp=(new Date).getTime();var f=c.timeStamp-(this._lastEvent&&this._lastEvent.timeStamp)||0,h=Math.abs(c.pageX-this._lastEvent.pageX)>e||Math.abs(c.pageY-this._lastEvent.pageY)>e;return fe.w&&(f.lw=e.w-f.dl),f.lh+f.dt>e.h&&(f.lh=e.h-f.dt),a.width(f.lw),a.height(f.lh),f.lwh=f.lw/2,f.lhh=f.lh/2,f.dlh=f.dl/2,f.dth=f.dt/2,f},_loadZoomed:function(){if(!this._imageLoaded)return"none"!=this.options.preload.zoomed&&(this._loadZoomedPromise=!0),void this._loadImage();if(!this._zoomLoaded&&!this._zoomLoading){var b=this;this._zoomLoading=!0,this._zoomLoaded=!1,this._toLoadCount=this.imgs.length,this._zoomLoadedCount=0,this._track("startPreload");var c=function(a){++b._zoomLoadedCount==b._toLoadCount&&(b._zoomLoaded=!0,b._zoomLoading=!1,b.loading.hide(),b._track("preloaded"),b._calcSize())};a.each(this.imgs,function(a,d){d.on("load",c),d[0].src=b._getUrl(b.options.zoom[a])})}},_checkLoaded:function(a){var b=this,c=!1;this._zoomLoading||this._loadZoomed(),clearInterval(this.interval),this.interval=setInterval(function(){b._zoomLoaded?(clearInterval(b.interval),b.zoom(b.zoomed,a,!0)):b._zoomLoading&&!c&&(b.canHideEl&&b.element.css({opacity:0}),c=!0)},50)},_pinchZoomStart:function(b){var c=this;this.zoomed=!0,this.options.fade?this.target.animate({opacity:1}):this.target.css({opacity:1}),this.target.show();var d={pw:this.overflow.width(),ph:this.overflow.height(),po:this.parent.offset(),mw:0,mh:0,lens:null};return d.tw=1*d.pw,d.th=1*d.ph,this.wrapper.css({width:this.overflow.width(),height:this.overflow.height()}),this.map&&(d.mw=this.map.width(),d.mh=d.mw*(this.element.height()/this.element.width()),d.mo=this.map.offset(),this.inner.height(d.mh),this.map.show(),this.lens&&(d.lens=this._makeLens(this.lens,d.mw,d.mh,1,{w:d.mw,h:d.mh})),this._mapEnd=function(b){c.inner.off("touchmove",a.proxy(c._mapMove,c)),c.inner.off("touchend",a.proxy(c._mapEnd,c))},this._mapMove=function(a){a.preventDefault(),a.stopPropagation(),c._mouseMove(c._getEvent(a),d.pw,d.ph,d.tw,d.th,c.map.offset(),null,null,d.mw,d.mh,d.lens,!0)},this._mapStart=function(b){b.preventDefault(),b.stopPropagation(),c._mouseMove(c._getEvent(b),d.pw,d.ph,d.tw,d.th,c.map.offset(),null,null,d.mw,d.mh,d.lens,!0),this.inner.on("touchmove",a.proxy(c._mapMove,c)),this.inner.on("touchend",a.proxy(c._mapEnd,c))},this.inner.on("touchstart",a.proxy(this._mapStart,this)),this.inner.removeClass(this.options.states.inactive).addClass(this.options.states.active),this.inner.show(),this.lens&&this.lens.show()),this._parentMove=function(a){return c.hasPinchEnded?!!(a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&1!=a.originalEvent.touches.length)||(a.preventDefault(),1!==this.zoomBy&&a.stopPropagation(),void c._mouseMove(c._getEvent(a),d.pw,d.ph,d.tw,d.th,d.po,null,null,d.mw,d.mh,d.lens)):(a.stopPropagation(),!0)},this.parent.on("touchmove",a.proxy(this._parentMove,this)),d},_pinchZoom:function(a,b,c,d){b==this.maxZoom?this._track("maxZoom",{domEvent:a,scale:b,center:c}):1==b&&this._track("minZoom",{domEvent:a,scale:b,center:c}),d.tw=d.pw*b,d.th=d.ph*b,this.zoomBy=b,this.wrapper.css({width:d.tw,height:d.th}),this.lens&&(d.lens=this._makeLens(this.lens,d.mw,d.mh,b,{w:d.mw,h:d.mh})),this._mouseMove({currentTarget:a.currentTarget,pageX:c.x,pageY:c.y},d.pw,d.ph,d.tw,d.th,d.po,null,null,d.mw,d.mh,d.lens)},_mouseMove:function(a,b,c,d,e,f,g,h,i,j,k,l){var m,n,o,p,q,r=g?d-b+(b-g):d-b,s=h?e-c+(c-h):e-c;if(this.init&&this.options.pan){if(!(this.mousedown||this.canTouch||l))return void(this.panning=!1);if(this.pinching)m=(this.startPos.x+(this.pos.start.x-f.left))/this.startZoom,n=(this.startPos.y+(this.pos.start.y-f.top))/this.startZoom,o=r*(m/b),p=s*(n/c);else{this.panning=!0;var t=this.pos.start.x-a.pageX,u=this.pos.start.y-a.pageY;o=t+this.pos.cur.x,p=u+this.pos.cur.y,m=(o+b/2)/(d/b),n=(p+c/2)/(e/c)}}else this.init=!0,this.panning=!1,m=a.pageX-f.left,n=a.pageY-f.top,o=r*(m/b),p=s*(n/c),this.pos.cur.x=this.pos.last.x||o,this.pos.cur.y=this.pos.last.y||p;if(this.lens){if(this.box){this.box[0].lastChild.relatedUUID!=this.uuid&&(this.box.append(this.wrapper),this.wrapper.show().siblings().hide());var v=b,w=c,x=m-k.lwh-k.dlh,y=n-k.lhh-k.dth;o=(x+k.dlh)*this.zoomBy-k.lw/b,p=(y+k.dth)*this.zoomBy-k.lh/c,q=this._setBounds(m,n,b,c,0,0),m=q.x,n=q.y}else if(l){this.panning&&(m=a.pageX-f.left,n=a.pageY-f.top);var v=i,w=j,x=m-k.lwh-k.dlh,y=n-k.lhh-k.dth;o=((x+k.dlh)*this.zoomBy-k.lw/b)*b/i,p=((y+k.dth)*this.zoomBy-k.lh/c)*c/j,this.pos.cur={x:o,y:p}}else if(this.map){if(this.map[0].lastChild.relatedUUID!=this.uuid&&(this.map.append(this.inner),this.inner.show().siblings().hide()),this.panning){var x=m/(b/i)-k.lwh-k.dth;y=n/(c/j)-k.lhh-k.dth}else var z=m/(b/k.lw),A=n/(c/k.lh),x=m/(b/i)-z-k.dlh,y=n/(c/j)-A-k.dth;q=this._setBounds(x,y,i-k.lw-k.dl,j-k.lh-k.dt,0,0),x=q.x,y=q.y}(this.box||l)&&(m+k.lwh+k.dlh>=v&&(x=v-k.lw-k.dl),n+k.lhh+k.dth>=w&&(y=w-k.lh-k.dt),m-k.lwh-k.dlh<=0&&(x=0),n-k.lhh-k.dth<=0&&(y=0)),this.lens.css({top:y+"px",left:x+"px"})}q=this._setBounds(o,p,r,s,0,0),o=q.x,p=q.y,this.pos.last={x:o,y:p},this.lastPos={x:o,y:p},this.oldTarget&&this.oldTarget.css({top:-p+"px",left:-o+"px"}),this.target.css({top:-p+"px",left:-o+"px"}),this._track("move",{domEvent:a,pos:{x:m/b,y:n/c}})},_calcSize:function(){var a,b;if(this.options.responsive&&this.options.width&&this.options.height&&"auto"!=this.options.width&&"auto"!=this.options.height?(a=this.element.width(),b=a*(this.options.height/this.options.width),this.parent.height(b),this.overflow.height(b),0!=this.element.height()&&b>this.element.height()&&this.overflow.height(this.element.height())):(this.options.width&&this.parent.width(this.options.width),this.options.height&&this.parent.height(this.options.height)),this.map){var c=this.map.width(),d=c*(this.element.height()/this.element.width());this.inner.height(d)}},_getUrl:function(b){if(this.options.url)return this.options.url;var c=this.element.attr("src")||this.element.attr("data-amp-src");if(c){var d=this._cycle?b||1:this.options.zoom;c=this._cleanUrl(c);var e=this.options.transforms;if(this._cycle){e=e[a.inArray(b,this.options.zoom)]}return c=e?this._setTransforms(c,e):c,c=this._setWidth(c,{h:this._originalImage.height*d,w:this._originalImage.width*d})}},_getWidth:function(a){if(window.amp&&.di)return amp.di.width(a);var a=a.split("?");if(!a[1])return!1;for(var b=a[1].split("&"),c=0;c
'),this._imageLoading=!0;var b=this.element[0].src||this.element.attr("data-amp-src");this.element.on("load",a.proxy(this._onImageLoad,this)),this.element[0].src="",this.element[0].src=b}},_getNaturalSize:function(a){return{width:this.element[0].naturalWidth,height:this.element[0].naturalHeight}},_setTransforms:function(a,b){return a.indexOf("?")==-1?a+"?"+b:a+"&"+b},_setBounds:function(a,b,c,d,e,f){return a>=c&&(a=c),b>=d&&(b=d),a<=e&&(a=e),b<=f&&(b=f),{x:a,y:b}},_track:function(a,b){this._trigger(a,null,b),window.amp&&.stats&&.stats.event&&.stats.event(this.element,"zoom",a,b)},_setCursor:function(a,b){return"string"!=typeof a&&(a="auto"),a.indexOf("zoom")<0?(b.css("cursor",a),!1):!document.documentMode&&("undefined"!=typeof InstallTrigger&&b.css("cursor","-moz-"+a),void(window.chrome&&b.css("cursor","-webkit-"+a)))},_setZoomCursor:function(a){var b=this.options.zoom;if(b.length){b.indexOf(this.zoomBy)===b.length-1?this._setCursor(this.options.cursor.active,a):this._setCursor(this.options.cursor.inactive,a)}else this.zoomBy>1?this._setCursor(this.options.cursor.active,a):this._setCursor(this.options.cursor.inactive,a)},_getDistance:function(a){var b=Math.abs(a[0].pageX-a[1].pageX),c=Math.abs(a[0].pageY-a[1].pageY);return Math.sqrt(b*b+c*c)},_getPosition:function(a){return{x:(a[0].pageX+a[1].pageX)/2,y:(a[0].pageY+a[1].pageY)/2}},_destroy:function(){this.element.unwrap().unwrap(),this.wrapper.remove(),this.element.removeClass("amp"),this.element.removeClass("amp-zoom"),this.element.removeClass(this.options.states.active),this.element.removeClass(this.options.states.inactive),this.element.css({cursor:"",height:"","max-width":"",width:"",opacity:"",position:"",display:"",top:"",left:"",zoom:""}),this._removeEmptyAttributeHelper(this.element)},_removeEmptyAttributeHelper:function(a,b){for(var c=b||["class","style"],d=0,e=c.length;d1&&b.stopPropagation(),this.panner&&(this.panner.remove(),delete this.panner),this.scale>1&&(this.panner=new d(this,b,a.proxy(function(a,b){this.zoomArea&&this.zoomArea.setPosition(a,b)},this))),!0},this))),this.options.pinch&&this.element.parent().on("touchstart",a.proxy(function(b){return this_touchmove=!1,this.pincher&&(this.pincher.remove(),delete this.pincher),this.pincher=new c(b,a.proxy(function(){this.zoomIn()},this),a.proxy(function(){this.zoomOut()},this)),!0},this)),""!==this.options.stopPropagation&&this.element.parent().on(this.options.stopPropagation,a.proxy(function(a){1!=this.scale&&a.stopPropagation()},this))},visible:function(a){this._visible!=a&&(a?"visible"==this.options.preload&&this.load():this.options.preventVisibleZoomOut||this.zoomOutFull(),this._track("visible",{visible:a}),this._visible=a)},load:function(){this._setupZoomArea().then(a.proxy(function(a){this.zoomArea.allowClone=!0,a.setScale(this.options.zoom)},this))},_setupZoomArea:function(){return new Promise(a.proxy(function(b,c){this.zoomArea?b(this.zoomArea):this.getImageSize().then(a.proxy(function(d){if(d.error)c(!1);else{var f=this,g=new Image;g.src=this.element.attr("src");var h=a('
');this.$parent.append(h),this.zoomArea=new e(this.element,this.$parent,d,this.options.transforms,this.options),g.onload=function(){h.remove(),b(f.zoomArea)}}},this))},this))},getImageSize:function(){return new Promise(a.proxy(function(b,c){this.element[0].naturalWidth&&this.element[0].naturalHeight?b({x:this.element[0].naturalWidth,y:this.element[0].naturalHeight}):this.element[0].width&&this.element[0].height&&b({x:this.element[0].width,y:this.element[0].height}),this.element.on("load",a.proxy(function(){this.element[0].naturalWidth&&this.element[0].naturalHeight?b({x:this.element[0].naturalWidth,y:this.element[0].naturalHeight}):this.element[0].width&&this.element[0].height&&b({x:this.element[0].width,y:this.element[0].height})},this)),this.element.on("error",a.proxy(function(){c({error:!0})},this))},this))},_invalidateParentSize:function(){this.parentSize={x:this.$parent.width(),y:this.$parent.height()}},state:function(){return{scale:this.scale,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep}},zoomInFull:function(a){ this.setScale(this.options.scaleMax),this._track("zoomedInFull",{domEvent:a,scale:this.options.scaleMax,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep})},zoomIn:function(b){var c=this;if(!c.zoomArea)return c._setupZoomArea().then(function(a){a&&c.zoomIn(b)}),!1;if((this.options.scaleSteps||1==this.scale)&&(b&&b.preventDefault(),(this.options.activation.inGesture||!this.gestureDetect.detected)&&(!c.zoomArea||!c.zoomArea.animating))){this.scale==this.options.scaleMax&&this.options.events.zoomIn&&(c.zoomArea.$container.off(this.options.events.zoomIn,this.zoomIn),c.isZoomIn=!1);var d=this.scale;this.options.scaleSteps?(this.scale+=this.options.scaleStep,this.scale=Math.min(this.scale,this.options.scaleMax)):this.scale=this.options.scaleMax,d!=this.scale&&(this._track("zoomedIn",{domEvent:b,scale:this.scale,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep}),this.setScale(this.scale).then(function(){setTimeout(a.proxy(function(){!c.isMoveOn&&c.options.events.move&&(c.zoomArea.$container.on(this.options.events.move,a.proxy(c._setPos,c)),c.isMoveOn=!0),c.options.scaleProcess?c.options.scaleSteps&&c.scale!=c.options.scaleMax?c.isZoomIn||(c.zoomArea.$container.on(this.options.events.zoomIn,a.proxy(c.zoomIn,c)),c.isZoomIn=!0):c.zoomArea.$container.on(c.options.events.zoomOut,a.proxy(c.zoomOut,c)):c.options.scaleSteps||c.zoomArea.$container.on(c.options.events.zoomOut,a.proxy(c.zoomOut,c))},c),500)}))}},zoomInClick:function(b){if(this.options.activation.inGesture||!this.gestureDetect.detected){var c=this.scale;this.scale+=this.options.scaleStep,this.scale=Math.min(this.scale,this.options.scaleMax),c!=this.scale&&(this._track("zoomedIn",{domEvent:b,scale:this.scale,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep}),this.setScale(this.scale),setTimeout(a.proxy(function(){self.zoomArea.$container.on(this.options.events.move,a.proxy(this._setPos,this))},this),1))}},setScale:function(b){return this.scale=b,this._setupZoomArea().then(a.proxy(function(a){a&&(a.setScale(this.scale),this._invalidateParentSize())},this))},_setPos:function(a){"touchmove"===a.type&&(this._touchmove=!0),this._track("settingPos",{domEvent:a});var b=a?this._getPercentagePos(a):{x:.5,y:.5};this.zoomArea.setPosition(b.x,b.y)},zoomOut:function(a){if(this.zoomArea.allowClone=!1,this._touchmove)return!1;if(!this.zoomArea||!this.zoomArea.animating){var b=this.scale;this.options.scaleSteps?(this.scale-=this.options.scaleStep,this.scale=Math.max(this.scale,1)):this.scale=1,b!=this.scale&&(1==this.scale&&(this.options.events.move&&(this.zoomArea.$container.off(this.options.events.move,this._setPos),this.isMoveOn=!1),this.options.events.zoomOut&&this.zoomArea.$container.off(this.options.events.zoomOut,this.zoomOut)),this.zoomArea.setScale(this.scale),this._track("zoomedOut",{domEvent:a,scale:this.scale,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep}))}},zoomOutFull:function(a){this.zoomArea&&(this.options.events.move&&self.zoomArea.$container.off(this.options.events.move,this._setPos),this.options.events.zoomOut&&self.zoomArea.$container.off(this.options.events.zoomOut,this.zoomOut),this.scale=1,this.zoomArea.setScale(1),this._track("zoomedOutFull",{domEvent:a,scale:this.scale,scaleMax:this.options.scaleMax,scaleStep:this.options.scaleStep}))},_convertEvent:function(a){return a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&(a.preventDefault(),a=a.originalEvent.touches[0]),a},_getPercentagePos:function(a){a=this._convertEvent(a);var b=this.$parent.offset();return{x:(a.pageX-b.left)/this.parentSize.x,y:(a.pageY-b.top)/this.parentSize.y}},_track:function(a,b){this._trigger(a,null,b),window.amp&&.stats&&.stats.event&&.stats.event(this.element,"zoom",a,b)},_destroy:function(){this.element.removeClass("amp"),this.element.removeClass("amp-zoom"),this._removeEmptyAttributeHelper(this.element)},_removeEmptyAttributeHelper:function(a,b){for(var c=b||["class","style"],d=0,e=c.length;dthis.threshold&&(this.cbIn(),this.start=b),c<0-this.threshold&&(this.cbOut(),this.start=b)},c.prototype.remove=function(){this.end()},c.prototype.end=function(b){a(document).off("mousemove touchmove",this.move),a(document).off("mouseup touchend",this.end)},c.prototype.getFingers=function(a){return a.originalEvent&&a.originalEvent.touches&&(a=a.originalEvent.touches),a};var d=function(b,c,d){this.multiFinger(c)||(c=this.convertEvent(c),this.start={x:c.pageX,y:c.pageY},this.zoomArea=b.zoomArea,this.cb=d,this.element=b.element,this.zoomArea.newSize||(this.zoomArea.newSize={x:this.zoomArea.$source.width(),y:this.zoomArea.$source.height()}),this.currentPixPos=this.zoomArea.getPixPos(),a(document).on("mousemove touchmove",a.proxy(this.move,this)),a(document).on("mouseup touchend",a.proxy(this.end,this)))};d.prototype.move=function(a){a.preventDefault(),a=this.convertEvent(a);var b=a.pageX-this.start.x,c=a.pageY-this.start.y,d=this.zoomArea.getPercentFromPos(this.currentPixPos.x+b,this.currentPixPos.y+c);this.cb(d.x,d.y)},d.prototype.end=function(b){a(document).off("mousemove touchmove",this.move),a(document).off("mouseup touchend",this.end)},d.prototype.remove=function(){this.end()},d.prototype.multiFinger=function(a){return a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches.length>1},d.prototype.convertEvent=function(a){return a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&(a=a.originalEvent.touches[0]),a};var e=function(a,b,c,d,e){this.options=e,this.animating=!1,this._allowChangeClone=!0,this.isFF=navigator.userAgent.toLowerCase().search("firefox")>-1,this.transforms=d,this.initialSrc=a[0].src,this.scale=1,this.$area=b,this.$source=a,this.originalSize=c,this.posPercentageX=.5,this.posPercentageY=.5,this.createContainer(),this.hide()};e.prototype.getPercentagePosWithScale=function(a){},e.prototype.createContainer=function(){var b=this;this.$container=a('
'),this.$preloader=new Image,a(this.$preloader).on("load",function(){b._preloaderImgLoaded=!0,b.allowClone&&!b.animating&&b.updateImageSrc(!0)}),this.$zoomed=a(''),this.$zoomedClone=a(''),this.$container.append(this.$zoomedClone),this.$container.append(this.$zoomed),this.$area.append(this.$container),this.$container.css({position:"absolute",top:0,left:0,bottom:0,right:0})},e.prototype.invalidatePosition=function(){this.setPosition(this.posPercentageX,this.posPercentageY)},e.prototype.setPosition=function(a,b){this.animating||(this.$zoomed.width()<=this.$area.width()&&(a=.5),this.$zoomed.height()<=this.$area.height()&&(b=.5),this.posPercentageX=a,this.posPercentageY=b,a=Math.min(1,Math.max(0,a)),b=Math.min(1,Math.max(0,b)),this.$zoomed.css("left",0-(this.$zoomed.width()-this.$area.width())*a+"px"),this.$zoomed.css("top",0-(this.$zoomed.height()-this.$area.height())*b+"px"),this.$zoomedClone.css("left",0-(this.$zoomed.width()-this.$area.width())*a+"px"),this.$zoomedClone.css("top",0-(this.$zoomed.height()-this.$area.height())*b+"px"))},e.prototype.getPixPos=function(a,b){return void 0==a&&void 0==b&&(a=this.posPercentageX,b=this.posPercentageY),a=Math.min(1,Math.max(0,a)),b=Math.min(1,Math.max(0,b)),{x:0-(this.newSize.x-this.$area.width())*a,y:0-(this.newSize.y-this.$area.height())*b}},e.prototype.getPercentFromPos=function(a,b){return{x:0-a/(this.newSize.x-this.$area.width()),y:0-b/(this.newSize.y-this.$area.height())}},e.prototype.animate=function(b,c,d){this.animating=!0,b.x<=this.$area.width()&&(c.x=this.getPixPos(.5,.5).x),b.y<=this.$area.height()&&(c.y=this.getPixPos(.5,.5).y);var e={width:b.x,height:b.y,left:c.x+"px",top:c.y+"px"};this.$zoomed.animate(e,500),this.$zoomedClone.animate(e,500),setTimeout(a.proxy(function(){d&&d(),this.animating=!1},this),this.isFF?1e3:600)},e.prototype.updateImageSrc=function(a){var b=this;if(!a||!b.allowClone||!b._preloaderImgLoaded)return!1;b.setImage()},e.prototype.setScale=function(a,b){var c=this,d=a>this.scale;a!=this.scale&&(this.allowClone=!!d,c._preloaderImgLoaded=!1,athis.scale&&(this.$zoomed.width(this.$source.width()),this.$zoomed.height(this.$source.height()),this.$zoomedClone.width(this.$source.width()),this.$zoomedClone.height(this.$source.height())),this.setPosition(.5,.5),this.show()),1==a?this.animate(this.newSize,this.getPixPos(),function(){c.hide(),c.updateImageSrc(!1)}):this.animate(this.newSize,this.getPixPos(),function(){c.updateImageSrc(d)}),this.scale=a,this.invalidateImageURL({x:this.originalSize.x*a,y:this.originalSize.y*a}))},e.prototype.show=function(){this.invalidatePosition(),a(window).off("resize",this.invalidatePosition),a(window).on("resize",a.proxy(this.invalidatePosition,this)),this.$container.show()},e.prototype.hide=function(){this.$container.hide(),a(window).off("resize",this.invalidatePosition)},e.prototype.invalidateImageURL=function(a){var b=this,c="";this.transforms&&this.transforms.length&&(c=this.transforms+"&");var d=this.initialSrc.split("?")[0]+"?"+c+"w="+a.x+"&h="+a.y;0!=a.x&&0!=a.y||(d=""),b.$preloader=new Image,b._preloaderImgLoaded=!0,b.$preloader.setAttribute("src",d)},e.prototype.setImage=function(){var a,b=this,c=b.$zoomed.attr("src");if(b._allowChangeClone&&b.$zoomedClone.attr("src",c),b.$preloader.complete&&b.$preloader.naturalWidth&&b.$preloader.naturalWidth>0){if(a)return;setTimeout(function(){b.$zoomed.attr("src",b.$preloader.src)},b.isFF?1e3:10),a=!0}else b.$preloader.onload=function(){a||(b.$zoomed.attr("src",b.$preloader.src),a=!0)};b._allowChangeClone=!1}}(jQuery),function(a){a.widget("amp.ampVideo",{options:{autoplay:!1,loop:!1,muted:!1,skin:"",responsive:!0,preload:"auto",pauseOnHide:!0,controls:!0,nativeControlsForTouch:!0,plugins:{},enableSoftStates:!0},_states:{stopped:0,buffering:1,paused:2,playing:3,loading:4,error:5,idle:6},_currentState:0,_ready:!1,_loopCount:0,_savedHTML:"",_getCreateOptions:function(){this._savedHTML=this.element[0].outerHTML;var b=this.element.data().ampVideo;return b?a.extend(!0,{},this.options,b):this.options},_create:function(){this.element.addClass("amp amp-video");var b=this.element.find("video"),c=this;b.addClass("video-js "+this.options.skin+" vjs-big-play-centered"),videojs&&(videojs.options.flash.swf=this.options.swfUrl+"video-js.swf"||"../../assets/video-js.swf",this._player=videojs(b[0],{autoplay:this.options.autoplay,muted:this.options.muted,width:"100%",height:"100%",loop:!1,controls:this.options.controls,preload:this.options.preload,plugins:c._sanitisePlugins(this.options.plugins),nativeControlsForTouch:this.options.nativeControlsForTouch})),c._calcSize(),c.options.responsive&&a(window).bind("resize",function(a){return function(){return a._calcSize()}}(c)),this._player.ready(function(){this.options_.muted&&this.volume(0),c._ready=!0;var b=c.element.find(".vjs-tech"),d=setInterval(function(){if("auto"==c.options.height){var a=b.css({height:"auto"}).height();0!=a&&(clearInterval(d),c.element.height(a),b.css({height:""}),c._player.dimensions(c.element.width(),c.element.height()))}},200);c.options.autoplay&&c.state(c._states.playing),c.options.plugins&&c.options.plugins.videoJsResolutionSwitcher&&c.options.plugins.videoJsResolutionSwitcher.default&&(c._player.on("ready",function(){c._player.currentResolution(c.options.plugins.videoJsResolutionSwitcher.default),c._allowResolutionChange=!1}),c._player.on("resolutionchange",function(){c._player.paused()&&(c._allowResolutionChange&&(c._player.play(),c._player.pause()),c._player.currentTime()>.5&&(c._allowResolutionChange=!0))})),this.on("play",function(a){c.softPlay&&c.options.enableSoftStates?c.softPlay=!1:(c.state(c._states.playing),c._track("play",{event:a,player:this,time:this.currentTime(),duration:c.duration}))}),this.on("error",function(a){c.state(c._states.error),c._track("error",null)}),this.on("pause",function(a){a.target.ended||a.target.seeking||(c.state(c._states.paused),c._track("pause",{event:a,player:this,time:this.currentTime(),duration:c.duration}))}),this.on("waiting",function(a){c.state(c._states.buffering)}),this.on("seeking",function(a){c.softSeek?c.softSeek=!1:(c.state()!==c._states.paused&&0!==a.target.currentTime&&c.options.enableSoftStates&&(c.softPlay=!0),c._track("seeked",{event:a,player:this,time:this.currentTime(),duration:c.duration}))}),this.on("timeupdate",function(a){c._track("timeUpdate",{event:a,player:this,time:this.currentTime(),duration:c.duration})}),this.on("volumechange",function(a){c._track("volume",{event:a,player:this,volume:this.volume(),muted:this.muted()})}),this.on("durationchange",function(a){c.duration=this.duration(),c._track("durationChange",{event:a,player:this,duration:c.duration})}),this.on("fullscreenchange",function(b){c._track("fullScreenChange",{event:b,player:this}),setTimeout(function(){a(window).resize()},200)}),this.on("ended",function(a){c.options.loop?(c.softSeek=!0,c._player.currentTime(0),c.softPlay=!0,c._player.play(),c._track("ended",null),c._track("looped",{count:++c._loopCount})):(c.state(c._states.stopped),c._track("ended",null),c._track("stopped",null))}),c._track("created",{player:this,duration:c.duration})})},visible:function(a){a!=this._visible&&(this._track("visible",{visible:a}),a?this._calcSize():this._states.playing!=this.state()&&this._states.buffering!=this.state()||this.options.pauseOnHide&&this.pause(),this._visible=a)},redraw:function(){this._calcSize()},_calcSize:function(){var a,b;if(this.options.responsive&&this.options.width&&this.options.height&&"auto"!=this.options.width&&"auto"!=this.options.height){var c=this.element.css("display");this.element.css("display","block"),a=Math.round(this.element.width()),this.element.css("display",c),b=Math.round(a*(this.options.height/this.options.width)),this.element.height(b)}else this.options.width?this.element.width(this.options.width):this.options.responsive&&this.element.width(this.element.parent().width()),this.options.height?this.element.height(this.options.height):this.options.responsive&&this.element.height(this.element.parent().height());if(this.options.center){var d=this.element.height(),e=this.element.parent().height();this.element.css("margin-top",e/2-d/2+"px")}this._player&&this._player.dimensions(this.element.width(),this.element.height())},play:function(){this._ready&&this._states.playing!==this.state()&&this._player.play()},pause:function(){this._ready&&this._states.paused!==this.state()&&this._player.pause()},stop:function(){this._ready&&this._states.stopped!==this.state()&&(this._player.pause(),this.softSeek=!0,this._player.currentTime(0),this._track("stopped",null),this.state(this._states.stopped))},seek:function(a){this._ready&&this.currentTime(a)},currentTime:function(a){if(void 0===a)return this._player.currentTime();this._player.currentTime(a)},state:function(a){if(void 0===a)return this._currentState;this._currentState=a,this._trigger("stateChange",null,{state:a})},_track:function(a,b){this._trigger(a,null,b),window.amp&&.stats&&.stats.event&&.stats.event(this.element,"video",a,b)},_destroy:function(){this._player.dispose(),this._player=null,this.element[0].outerHTML=this._savedHTML},_sanitisePlugins:function(a){return a&&0==a.videoJsResolutionSwitcher&&delete a.videoJsResolutionSwitcher,a}})}(jQuery),function(a){a.widget("amp.ampSpin",a.amp.ampStack,{options:{delay:50,autoplay:!1,loop:!0,responsive:!0,states:{selected:"amp-selected",seen:"amp-seen",active:"amp-active",inactive:"amp-inactive"},events:{start:"mousedown touchstart",move:"mousemove touchmove",end:"mouseup touchend"},momentum:!0,preload:"created",preloadType:"full",minDistance:25,activate:"down",friction:.97,dir:"normal",gesture:{enabled:!0,fingers:1},orientation:"horz",start:1,cursor:{active:"auto",inactive:"auto"},play:{onLoad:!1,onVisible:!1,repeat:1,delay:10},dragDistance:200,lazyLoad:!1},_getCreateOptions:function(){var b=this.element.data().ampSpin;return b?a.extend(!0,{},this.options,b):this.options},_create:function(){var b=this,c=this._children=this.element.children();this._count=this.element.children().length;this.isWebkit=/Chrome|Safari/.test(navigator.userAgent)&&!/Edge/.test(navigator.userAgent),this.$document=a(document),this.options.friction=Math.min(this.options.friction,.999),this.options.friction=Math.max(this.options.friction,0),this._setCursor(this.options.cursor.inactive),this.count=this.element.children().length,this.options.dragDistance=Math.max(this.options.dragDistance,1),this._index=Math.max(1,Math.min(this.options.start,this.count)),a.inArray(this.options.preload,["created","visible","none"])==-1&&(this.options.preload="created"),this.element.addClass("amp"),this.element.addClass("amp-spin"),this.element.addClass(this.options.states.inactive),this.imgs=this.element.find("img:not(.amp-zoom-img)"),this.toLoadCount=this.imgs.length,this.loadedCount=0,c.addClass("amp-frame");var d=c.eq(this._index-1),e=d.clone();e.addClass("amp-frame-clone"),this.isWebkit?(c.css({display:"none"}),d.css("display","block")):(c.css({"z-index":-1}),d.css("z-index",1)),this.element.append(e),d.eq(this._index-1).addClass(this.options.states.selected+" "+this.options.states.seen),setTimeout(function(a){return function(){return a._calcSize()}}(b),1),this.options.responsive&&a(window).on("resize",function(a){return function(){return a._calcSize()}}(b)),this.element.on("dragstart",function(a){return!1}),this.element.on(this.options.events.start,a.proxy(this._startDrag,this)),this.element.on("mousewheel DOMMouseScroll",function(a){return b._mouseScroll(a)}),this.options.autoplay&&this.play(),"created"==this.options.preload&&this._startPreload(),this._track("created",{index:this._index,canNext:this.canNext(),canPrev:this.canPrev()})},_setCursor:function(a){return a.indexOf("zoom")<0&&a.indexOf("grab")<0?(this.element.css("cursor",a),!1):!document.documentMode&&("undefined"!=typeof InstallTrigger&&this.element.css("cursor","-moz-"+a),void(window.chrome&&this.element.css("cursor","-webkit-"+a)))},redraw:function(){this._calcSize()},_mouseScroll:function(a){var b=0;return a||(a=window.event),a.originalEvent.wheelDelta?b=a.originalEvent.wheelDelta:a.originalEvent.detail&&(b=-a.originalEvent.detail),b>0?this.next():this.prev(),this._track("scroll",{domEvent:a,delta:b}),a.preventDefault(),!1},visible:function(a){var b=this;a!=b._visible&&(b._super(a),a&&("visible"==b.options.preload&&b._startPreload(),"none"==this.options.preload&&b._startPreload(b._index),b.options.play.onVisible&&b._loaded&&setTimeout(function(){b.playRepeat(b.options.play.repeat)},b.options.play.delay)))},_resolveEventCoords:function(a){return a=a.originalEvent,a.touches&&a.touches.length?{x:a.touches[0].clientX,y:a.touches[0].clientY}:a.changedTouches&&a.changedTouches.length?{x:a.changedTouches[0].clientX,y:a.changedTouches[0].clientY}:{x:a.clientX,y:a.clientY}},_startPreload:function(b){if(!(this._loaded||this._loading&&!this.first)){var c=this;this._loading=!0,this.first||(this._track("startPreload"),"none"!=this.options.preload&&("full"==this.options.preloadType?(this.pre=a('
  • '),this.element.append(this.pre)):"window"==this.options.preloadType&&(this.progressIndicator=a('
    '),this.progressIndicator.find(".amp-progress-message").html(this.options.progressMessage||"Loading..."),this.progressIndicator.progress=c.progressIndicator.find(".amp-progress-bar"),this.progressIndicator.visible=!0,this.element.append(this.progressIndicator))));var d=function(a){if(++c.loadedCount>=c.toLoadCount&&!c._loaded)c._unsetLoadEvents(c.imgs),c._loaded=!0,c.pre&&c.pre.remove(),c.options.play.onLoad&&c.playRepeat(c.options.play.repeat),c._loading=!1,c.progressIndicator&&(c.progressIndicator.visible=!1,c.progressIndicator.remove()),c._track("preloaded");else{var b=c.loadedCount/c.toLoadCount*100;c.pre&&(c.pre.css("width",100-b+"%"),c.pre.css("left",b+"%")),c.progressIndicator&&c.progressIndicator.visible&&c.progressIndicator.progress.css("width",b+"%")}};b?(this.first=!0,this.toLoadCount-=1,this._callImageMethod(a(this.imgs[b-1]),d)):this._callImageMethod(this.imgs,d)}},_unsetLoadEvents:function(b){if(b)for(var c=0,d=b.length;c0)return!1;this.element.find(".amp-spin").each(function(c,d){var e=a(d).data()["amp-ampSpin"]||a(d).data().ampAmpSpin;e&&e._startDrag&&e._startDrag(b)})}},_mouseMove:function(a,b,c,d,e){if(this.options.gesture.enabled&&a.originalEvent&&a.originalEvent.touches&&a.originalEvent.touches[0]&&a.originalEvent.touches.length!=this.options.gesture.fingers)return!0;var f=this._resolveEventCoords(a),g=f.x-b.left,h=f.y-b.top,i=g-c,j=h-d,k=(this._mouseMoveInfo,{e:a,mx:g,my:h});return Math.abs(i)Math.abs(j)?this.moveDir="horz":this.moveDir=this.options.orientation,this._mouseMoveInfo.push(k),this._mouseMoveInfo.length>2&&this._mouseMoveInfo.shift(),this._moveSpin("horz"==this.options.orientation?i:j,a,e),this.options.orientation==this.moveDir?(a.preventDefault(),!1):void 0},_moveSpin:function(a,b,c){var d=Math.round(a/this.options.dragDistance*(this._count-1));"normal"==this.options.dir&&(d=0-d),this._track("move",{domEvent:b,distFromStart:a});var e=this._numToIndex(d+c);e!=this._index&&(this._checkLoop(e),this.goTo(e))},_checkLoop:function(a){Math.abs(this._index-a)>2&&(this._index>a?this._track("looped","forwards"):this._track("looped","backwards"))},_endDrag:function(a,b,c,d,e){"horz"==this.moveDir&&(a.preventDefault(),a.stopPropagation()),this.moveDir=null;var f=this;if(!this._ended&&(this._started=!1,this._ended=!0,this._track("endMove",{domEvent:a}),this.$document.off(this.options.events.end,this._ubind),this.$document.off(this.options.events.move,this._mbind),clearInterval(this._timer),this._setCursor(this.options.cursor.inactive),this.element.removeClass(this.options.states.active).addClass(this.options.states.inactive),this.options.momentum&&2==this._mouseMoveInfo.length)){var g=this._mouseMoveInfo,h=g[1].e.timeStamp-g[0].e.timeStamp,i="horz"==this.options.orientation?g[1].mx-g[0].mx:g[1].my-g[0].my;if(0==i||0==h)return;var j=i/h,k=j,l=this.options.friction,m="horz"==this.options.orientation?g[1].mx-c:g[1].my-d,n=0,o=0;if(Math.abs(m)0;)k-=(k-k*l)*Math.min(d,1),d-=1;n+=k*c,o+=c,f._moveSpin(n+m,a,e),Math.abs(k)>.1&&window.requestAnimationFrame(q)};return void window.requestAnimationFrame(q)}},_calcSize:function(){this._super(),this.progressIndicator&&this.progressIndicator.visible&&(this.progressIndicator.css("top",(parseInt(a(this.element.find("li")[0]).css("height"))-parseInt(this.progressIndicator.css("height")))/2+"px"),this.progressIndicator.css("left",(parseInt(a(this.element.find("li")[0]).css("width"))-parseInt(this.progressIndicator.css("width")))/2+"px"))},_getIndex:function(a){var b=this.element.children();if(a>b.length){if(!this.options.loop)return;a=1}else if(a<1){if(!this.options.loop)return;a=b.length}},_direction:function(a){for(var b=0,c=0,d=a;d!=this._index;)d>this._count?d=0:d++,b++;for(d=a;d!=this._index;)d<1?d=this._count:d--,c++;return cthis._count?e=1:e+d<1?e=this._count:e+=d;return e},_loopCount:function(a,b,c){for(var d=a?1:-1,e=b,f=0;e!=c;)f++,e+d>this._count?e=1:e+d<1?e=this._count:e+=d;return f},_animate:function(a){var b=this.element,c=b.children("li").eq(this._index-1),d=b.children("li").eq(a-1);this._index!=a&&(d.addClass(this.options.states.selected+" "+this.options.states.seen),this.isWebkit?(d.css("display","block"),c.css("display","none")):(d.css("zIndex",1),c.css("zIndex",-1)),c.removeClass(this.options.states.selected),this._setIndex(a),this._setIndex(a,!0))},_track:function(a,b){this._trigger(a,null,b),window.amp&&.stats&&.stats.event&&.stats.event(this.element,"spin",a,b)},_destroy:function(){this.element.removeClass("amp"),this.element.removeClass("amp-spin"),this.element.removeClass(this.options.states.active),this.element.removeClass(this.options.states.inactive),this.element.css("cursor",""),this.element.find(".amp-progress").remove(),this.element.find(".amp-loading").remove(),this._removeEmptyAttributeHelper(this.element);var b=this.element.children();b.removeClass("amp-frame"),b.removeClass(this.options.states.selected),b.removeClass(this.options.states.seen),b.css("display","");for(var c=0,d=b.length;c= 2.0.0-beta.1",7:">= 4.0.0"};b.REVISION_CHANGES=m;var n="[object Object]";d.prototype={constructor:d,logger:l.default,log:l.default.log,registerHelper:function(a,b){if(f.toString.call(a)===n){if(b)throw new h.default("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(f.toString.call(a)===n)f.extend(this.partials,a);else{if(void 0===b)throw new h.default('Attempting to register a partial called "'+a+'" as undefined');this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]},registerDecorator:function(a,b){if(f.toString.call(a)===n){if(b)throw new h.default("Arg not supported with multiple decorators");f.extend(this.decorators,a)}else this.decorators[a]=b},unregisterDecorator:function(a){delete this.decorators[a]}};var o=l.default.log;b.log=o,b.createFrame=f.createFrame,b.logger=l.default},function(a,b){"use strict";function c(a){return k[a]}function d(a){for(var b=1;b":">",'"':""","'":"'","`":"`","=":"="},l=/[&<>"'`=]/g,m=/[&<>"'`=]/,n=Object.prototype.toString;b.toString=n;var o=function(a){return"function"==typeof a};o(/x/)&&(b.isFunction=o=function(a){return"function"==typeof a&&"[object Function]"===n.call(a)}),b.isFunction=o;var p=Array.isArray||function(a){return!(!a||"object"!=typeof a)&&"[object Array]"===n.call(a)};b.isArray=p},function(a,b){"use strict";function c(a,b){var e=b&&b.loc,f=void 0,g=void 0;e&&(f=e.start.line,g=e.start.column,a+=" - "+f+":"+g);for(var h=Error.prototype.constructor.call(this,a),i=0;i0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):e(this);if(c.data&&c.ids){var g=d.createFrame(c.data);g.contextPath=d.appendContextPath(c.data.contextPath,c.name),c={data:g}}return f(b,c)})},a.exports=b.default},function(a,b,c){"use strict";var d=c(2).default;b.__esModule=!0;var e=c(4),f=c(5),g=d(f);b.default=function(a){a.registerHelper("each",function(a,b){function c(b,c,f){j&&(j.key=b,j.index=c,j.first=0===c,j.last=!!f,k&&(j.contextPath=k+b)),i+=d(a[b],{data:j,blockParams:e.blockParams([a[b],b],[k+b,null])})}if(!b)throw new g.default("Must pass iterator to #each");var d=b.fn,f=b.inverse,h=0,i="",j=void 0,k=void 0;if(b.data&&b.ids&&(k=e.appendContextPath(b.data.contextPath,b.ids[0])+"."),e.isFunction(a)&&(a=a.call(this)),b.data&&(j=e.createFrame(b.data)),a&&"object"==typeof a)if(e.isArray(a))for(var l=a.length;h=0?b:parseInt(a,10)}return a},log:function(a){if(a=e.lookupLevel(a),"undefined"!=typeof console&&e.lookupLevel(e.level)<=a){var b=e.methodMap[a];console[b]||(b="log");for(var c=arguments.length,d=Array(c>1?c-1:0),f=1;f= 4.0.0"],main:function(a,b,c,d,e){var f,g=a.lambda,h=a.escapeExpression;return'
  • \n
    \n \n
    \n
  • \n'},useData:!0})),Handlebars.registerPartial("main-container-list-spin-3d",this.amp.templates["main-container-list-spin-3d"]=Handlebars.template({1:function(a,b,c,d,e,f,g){var h;return'
  • \n
      \n'+(null!=(h=c.each.call(null!=b?b:{},null!=(h=null!=b?b.set:b)?h.items:h,{name:"each",hash:{},fn:a.program(2,e,0,f,g),inverse:a.noop,data:e}))?h:"")+"
    \n
  • \n"},2:function(a,b,c,d,e,f,g){var h,i,j=null!=b?b:{},k=c.helperMissing,l="function",m=a.escapeExpression,n=a.lambda;return'
  • \n \n
  • \n'},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e,f,g){var h;return'
  • \n
    \n
      \n'+(null!=(h=c.each.call(null!=b?b:{},null!=(h=null!=(h=null!=b?b.spin:b)?h.set:h)?h.items:h,{name:"each",hash:{},fn:a.program(1,e,0,f,g),inverse:a.noop,data:e}))?h:"")+"
    \n
  • \n\n"},useData:!0,useDepths:!0})),Handlebars.registerPartial("main-container-list-spin",this.amp.templates["main-container-list-spin"]=Handlebars.template({1:function(a,b,c,d,e,f,g){var h,i,j=null!=b?b:{},k=c.helperMissing,l="function",m=a.escapeExpression,n=a.lambda;return'
  • \n \n
  • \n'},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e,f,g){var h;return'
  • \n
    \n
      \n'+(null!=(h=c.each.call(null!=b?b:{},null!=(h=null!=(h=null!=b?b.spin:b)?h.set:h)?h.items:h,{name:"each",hash:{},fn:a.program(1,e,0,f,g),inverse:a.noop,data:e}))?h:"")+"
    \n
  • \n"},useData:!0,useDepths:!0})),Handlebars.registerPartial("main-container-list-video",this.amp.templates["main-container-list-video"]=Handlebars.template({1:function(a,b,c,d,e,f,g){var h,i,j=null!=b?b:{},k=c.helperMissing,l="function",m=a.escapeExpression,n=a.lambda;return' \n'},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e,f,g){var h,i=a.lambda,j=a.escapeExpression;return'
  • \n
    \n \n
    \n
  • \n"},useData:!0,useDepths:!0})),Handlebars.registerPartial("main-container-list",this.amp.templates["main-container-list"]=Handlebars.template({1:function(a,b,c,d,e,f,g){var h;return null!=(h=c.if.call(null!=b?b:{},null!=b?b.set:b,{name:"if",hash:{},fn:a.program(2,e,0,f,g),inverse:a.program(7,e,0,f,g),data:e}))?h:""},2:function(a,b,c,d,e,f,g){var h;return null!=(h=c.if.call(null!=b?b:{},null!=(h=null!=(h=null!=(h=null!=b?b.set:b)?h.items:h)?h[0]:h)?h.set:h,{name:"if",hash:{},fn:a.program(3,e,0,f,g),inverse:a.program(5,e,0,f,g),data:e}))?h:""},3:function(a,b,c,d,e,f,g){return" "+a.escapeExpression((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(null!=b?b:{},"main-container-list-spin-3d",{name:"renderPartial",hash:{locale:null!=g[1]?g[1].locale:g[1],templates:null!=g[1]?g[1].templates:g[1],spin:b},data:e}))+"\n"},5:function(a,b,c,d,e,f,g){return" "+a.escapeExpression((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(null!=b?b:{},"main-container-list-spin",{name:"renderPartial",hash:{locale:null!=g[1]?g[1].locale:g[1],templates:null!=g[1]?g[1].templates:g[1],spin:b},data:e}))+"\n"},7:function(a,b,c,d,e,f,g){var h;return null!=(h=c.if.call(null!=b?b:{},null!=b?b.media:b,{name:"if",hash:{},fn:a.program(8,e,0,f,g),inverse:a.program(10,e,0,f,g),data:e}))?h:""},8:function(a,b,c,d,e,f,g){return" "+a.escapeExpression((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(null!=b?b:{},"main-container-list-video",{name:"renderPartial",hash:{locale:null!=g[1]?g[1].locale:g[1],templates:null!=g[1]?g[1].templates:g[1],video:b},data:e}))+"\n"},10:function(a,b,c,d,e,f,g){return" "+a.escapeExpression((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(null!=b?b:{},"main-container-list-image",{name:"renderPartial",hash:{locale:null!=g[1]?g[1].locale:g[1],templates:null!=g[1]?g[1].templates:g[1],image:b},data:e}))+"\n"},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e,f,g){var h;return'
      \n'+(null!=(h=c.each.call(null!=b?b:{},null!=b?b.items:b,{name:"each",hash:{},fn:a.program(1,e,0,f,g),inverse:a.noop,data:e}))?h:"")+"
    \n"},useData:!0,useDepths:!0})),Handlebars.registerPartial("nav-container-list-item",this.amp.templates["nav-container-list-item"]=Handlebars.template({1:function(a,b,c,d,e){var f;return'
    \n \n
    \n'},2:function(a,b,c,d,e){return"spin-3d"},4:function(a,b,c,d,e){return"spin"},6:function(a,b,c,d,e){return'
    \n \n
    \n'},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e){var f,g=null!=b?b:{},h=a.lambda,i=a.escapeExpression;return"
  • \n"+(null!=(f=c.if.call(g,null!=(f=null!=b?b.item:b)?f.set:f,{name:"if",hash:{},fn:a.program(1,e,0),inverse:a.noop,data:e}))?f:"")+(null!=(f=c.if.call(g,null!=(f=null!=b?b.item:b)?f.media:f,{name:"if",hash:{},fn:a.program(6,e,0),inverse:a.noop,data:e}))?f:"")+' \n
    \n
  • \n'},useData:!0})),Handlebars.registerPartial("nav-container-list",this.amp.templates["nav-container-list"]=Handlebars.template({1:function(a,b,c,d,e,f,g){return" "+a.escapeExpression((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(null!=b?b:{},"nav-container-list-item",{name:"renderPartial",hash:{locale:null!=g[1]?g[1].locale:g[1],templates:null!=g[1]?g[1].templates:g[1],item:b},data:e}))+"\n"},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e,f,g){var h;return'
      \n'+(null!=(h=c.each.call(null!=b?b:{},null!=b?b.items:b,{name:"each",hash:{},fn:a.program(1,e,0,f,g),inverse:a.noop,data:e}))?h:"")+"
    \n"},useData:!0,useDepths:!0})),this.amp.templates.desktopFullView=Handlebars.template({compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e){var f,g=null!=b?b:{},h=c.helperMissing,i=a.escapeExpression,j=a.lambda;return'
    \n
    \n '+i((c.renderPartial||b&&b.renderPartial||h).call(g,"main-container-list",{name:"renderPartial",hash:{locale:null!=b?b.locale:b,templates:null!=b?b.templates:b,items:null!=b?b.items:b},data:e}))+'\n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n'},useData:!0}),this.amp.templates.desktopNormalView=Handlebars.template({1:function(a,b,c,d,e){var f;return"amp-"+a.escapeExpression((f=null!=(f=c.view||(null!=b?b.view:b))?f:c.helperMissing,"function"==typeof f?f.call(null!=b?b:{},{name:"view",hash:{},data:e}):f))+"-view"},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e){var f,g=null!=b?b:{},h=c.helperMissing,i=a.escapeExpression,j=a.lambda;return'
    \n
    \n
    \n '+i((c.renderPartial||b&&b.renderPartial||h).call(g,"main-container-list",{name:"renderPartial",hash:{locale:null!=b?b.locale:b,templates:null!=b?b.templates:b,items:null!=b?b.items:b},data:e}))+'\n
    \n Click to zoom\n \n
    \n
    \n
    \n
    \n
    \n \n
    \n'},useData:!0}),this.amp.templates.mobileNormalView=Handlebars.template({1:function(a,b,c,d,e){var f;return"mobile-"+a.escapeExpression((f=null!=(f=c.view||(null!=b?b.view:b))?f:c.helperMissing,"function"==typeof f?f.call(null!=b?b:{},{name:"view",hash:{},data:e}):f))+"-view"},3:function(a,b,c,d,e){return'
    \n
    \n
    \n'},compiler:[7,">= 4.0.0"],main:function(a,b,c,d,e){var f,g=null!=b?b:{},h=a.escapeExpression,i=a.lambda;return'
    \n
    \n '+h((c.renderPartial||b&&b.renderPartial||c.helperMissing).call(g,"main-container-list",{name:"renderPartial",hash:{locale:null!=b?b.locale:b,templates:null!=b?b.templates:b,items:null!=b?b.items:b},data:e}))+'\n
    \n
    \n \n \n
    \n
    \n \n
    \n'},useData:!0}),function(a){"use strict";Handlebars.registerHelper("renderPartial",function(a,b){if(!a)return console.error("No partial name given."),"";var c=Handlebars.partials[a];return c?new Handlebars.SafeString(c(b.hash)):(console.error("Couldnt find the compiled partial: "+a),"")})}(window),function(a){Array.prototype.map||(Array.prototype.map=function(a,b){var c,d,e;if(null==this)throw new TypeError(" this is null or not defined");var f=Object(this),g=f.length>>>0;if("function"!=typeof a)throw new TypeError(a+" is not a function");for(b&&(c=b),d=Array(g),e=0;g>e;){var h,i;e in f&&(h=f[e],i=a.call(c,h,e,f),d[e]=i),e++}return d});var b=a.detect=function(){var a=function(){},b={browser_parsers:[{regex:"^(Opera)/(\\d+)\\.(\\d+) \\(Nintendo Wii",family_replacement:"Wii",manufacturer:"Nintendo"},{regex:"(SeaMonkey|Camino)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)",family_replacement:"Camino",other:!0},{regex:"(Pale[Mm]oon)/(\\d+)\\.(\\d+)\\.?(\\d+)?",family_replacement:"Pale Moon (Firefox Variant)",other:!0},{regex:"(Fennec)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)",family_replacement:"Firefox Mobile"},{regex:"(Fennec)/(\\d+)\\.(\\d+)(pre)",family_replacment:"Firefox Mobile"},{regex:"(Fennec)/(\\d+)\\.(\\d+)",family_replacement:"Firefox Mobile"},{regex:"Mobile.*(Firefox)/(\\d+)\\.(\\d+)",family_replacement:"Firefox Mobile"},{regex:"(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?)",family_replacement:"Firefox ($1)"},{regex:"(Firefox)/(\\d+)\\.(\\d+)(a\\d+[a-z]*)",family_replacement:"Firefox Alpha"},{regex:"(Firefox)/(\\d+)\\.(\\d+)(b\\d+[a-z]*)",family_replacement:"Firefox Beta"},{regex:"(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(a\\d+[a-z]*)",family_replacement:"Firefox Alpha"},{regex:"(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(b\\d+[a-z]*)",family_replacement:"Firefox Beta"},{regex:"(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?",family_replacement:"Firefox ($1)"},{regex:"(Firefox).*Tablet browser (\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"MicroB",tablet:!0},{regex:"(MozillaDeveloperPreview)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?"},{regex:"(Flock)/(\\d+)\\.(\\d+)(b\\d+?)",family_replacement:"Flock",other:!0},{regex:"(RockMelt)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Rockmelt",other:!0},{regex:"(Navigator)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Netscape"},{regex:"(Navigator)/(\\d+)\\.(\\d+)([ab]\\d+)",family_replacement:"Netscape"},{regex:"(Netscape6)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Netscape"},{regex:"(MyIBrow)/(\\d+)\\.(\\d+)",family_replacement:"My Internet Browser",other:!0},{regex:"(Opera Tablet).*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?",family_replacement:"Opera Tablet",tablet:!0},{regex:"(Opera)/.+Opera Mobi.+Version/(\\d+)\\.(\\d+)",family_replacement:"Opera Mobile"},{regex:"Opera Mobi",family_replacement:"Opera Mobile"},{regex:"(Opera Mini)/(\\d+)\\.(\\d+)",family_replacement:"Opera Mini"},{regex:"(Opera Mini)/att/(\\d+)\\.(\\d+)",family_replacement:"Opera Mini"},{regex:"(Opera)/9.80.*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?",family_replacement:"Opera"},{regex:"(OPR)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?",family_replacement:"Opera"},{regex:"(webOSBrowser)/(\\d+)\\.(\\d+)",family_replacement:"webOS"},{regex:"(webOS)/(\\d+)\\.(\\d+)",family_replacement:"webOS"},{regex:"(wOSBrowser).+TouchPad/(\\d+)\\.(\\d+)",family_replacement:"webOS TouchPad"},{regex:"(luakit)",family_replacement:"LuaKit",other:!0},{regex:"(Lightning)/(\\d+)\\.(\\d+)([ab]?\\d+[a-z]*)",family_replacement:"Lightning",other:!0},{regex:"(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?) \\(Swiftfox\\)",family_replacement:"Swiftfox",other:!0},{regex:"(Firefox)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)? \\(Swiftfox\\)",family_replacement:"Swiftfox",other:!0},{regex:"rekonq",family_replacement:"Rekonq",other:!0},{regex:"(conkeror|Conkeror)/(\\d+)\\.(\\d+)\\.?(\\d+)?",family_replacement:"Conkeror",other:!0},{regex:"(konqueror)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Konqueror",other:!0},{regex:"(WeTab)-Browser",family_replacement:"WeTab",other:!0},{regex:"(Comodo_Dragon)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Comodo Dragon",other:!0},{regex:"(YottaaMonitor)",family_replacement:"Yottaa Monitor",other:!0},{regex:"(Kindle)/(\\d+)\\.(\\d+)",family_replacement:"Kindle"},{regex:"(Symphony) (\\d+).(\\d+)",family_replacement:"Symphony",other:!0},{regex:"Minimo",family_replacement:"Minimo",other:!0},{regex:"(Edge)/(\\d+)\\.(\\d+)",family_replacement:"Edge"},{regex:"(CrMo)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Chrome Mobile"},{regex:"(CriOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Chrome Mobile iOS"},{regex:"(Chrome)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+) Mobile",family_replacement:"Chrome Mobile"},{regex:"(chromeframe)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Chrome Frame"},{regex:"(UC Browser)(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"UC Browser",other:!0},{regex:"(SLP Browser)/(\\d+)\\.(\\d+)",family_replacement:"Tizen Browser",other:!0},{regex:"(Epiphany)/(\\d+)\\.(\\d+).(\\d+)",family_replacement:"Epiphany",other:!0},{regex:"(SE 2\\.X) MetaSr (\\d+)\\.(\\d+)",family_replacement:"Sogou Explorer",other:!0},{regex:"(Pingdom.com_bot_version_)(\\d+)\\.(\\d+)",family_replacement:"PingdomBot",other:!0},{regex:"(facebookexternalhit)/(\\d+)\\.(\\d+)",family_replacement:"FacebookBot"},{regex:"(Twitterbot)/(\\d+)\\.(\\d+)",family_replacement:"TwitterBot"},{regex:"(AdobeAIR|Chromium|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Shiira|Sunrise|Chrome|Flock|Netscape|Lunascape|WebPilot|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iron|Iris|UP\\.Browser|Bunjaloo|Google Earth|Raven for Mac)/(\\d+)\\.(\\d+)\\.(\\d+)"},{regex:"(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Iron|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris)/(\\d+)\\.(\\d+)"},{regex:"(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\\d+)\\.(\\d+)\\.(\\d+)"},{regex:"(iCab|Lunascape|Opera|Android|Jasmine|Polaris|BREW) (\\d+)\\.(\\d+)\\.?(\\d+)?"},{regex:"(Android) Donut",v2_replacement:"2",v1_replacement:"1"},{regex:"(Android) Eclair",v2_replacement:"1",v1_replacement:"2"},{regex:"(Android) Froyo",v2_replacement:"2",v1_replacement:"2"},{regex:"(Android) Gingerbread",v2_replacement:"3",v1_replacement:"2"},{regex:"(Android) Honeycomb",v1_replacement:"3"},{regex:"(IEMobile)[ /](\\d+)\\.(\\d+)",family_replacement:"IE Mobile"},{regex:"(MSIE) (\\d+)\\.(\\d+).*XBLWP7",family_replacement:"IE Large Screen"},{regex:"(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+)"},{regex:"(Firefox)/(\\d+)\\.(\\d+)(pre|[ab]\\d+[a-z]*)?"},{regex:"(Obigo)InternetBrowser",other:!0},{regex:"(Obigo)\\-Browser",other:!0},{regex:"(Obigo|OBIGO)[^\\d]*(\\d+)(?:.(\\d+))?",other:!0},{regex:"(MAXTHON|Maxthon) (\\d+)\\.(\\d+)",family_replacement:"Maxthon",other:!0},{regex:"(Maxthon|MyIE2|Uzbl|Shiira)",v1_replacement:"0",other:!0},{regex:"(PLAYSTATION) (\\d+)",family_replacement:"PlayStation",manufacturer:"Sony"},{regex:"(PlayStation Portable)[^\\d]+(\\d+).(\\d+)",manufacturer:"Sony"},{regex:"(BrowseX) \\((\\d+)\\.(\\d+)\\.(\\d+)",other:!0},{regex:"(POLARIS)/(\\d+)\\.(\\d+)",family_replacement:"Polaris",other:!0},{regex:"(Embider)/(\\d+)\\.(\\d+)",family_replacement:"Polaris",other:!0},{regex:"(BonEcho)/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Bon Echo",other:!0},{regex:"(iPod).+Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPod).*Version/(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPod)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPhone).*Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPhone).*Version/(\\d+)\\.(\\d+)", -family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPhone)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPad).*Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(iPad).*Version/(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(iPad)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(AvantGo) (\\d+).(\\d+)",other:!0},{regex:"(Avant)",v1_replacement:"1",other:!0},{regex:"^(Nokia)",family_replacement:"Nokia Services (WAP) Browser",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)\\.(\\d+)",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+)",manufacturer:"Nokia"},{regex:"(BrowserNG)/(\\d+)\\.(\\d+).(\\d+)",family_replacement:"NokiaBrowser",manufacturer:"Nokia"},{regex:"(Series60)/5\\.0",v2_replacement:"0",v1_replacement:"7",family_replacement:"NokiaBrowser",manufacturer:"Nokia"},{regex:"(Series60)/(\\d+)\\.(\\d+)",family_replacement:"Nokia OSS Browser",manufacturer:"Nokia"},{regex:"(S40OviBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Nokia Series 40 Ovi Browser",manufacturer:"Nokia"},{regex:"(Nokia)[EN]?(\\d+)",manufacturer:"Nokia"},{regex:"(PlayBook).+RIM Tablet OS (\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Blackberry WebKit",tablet:!0,manufacturer:"Nokia"},{regex:"(Black[bB]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Blackberry WebKit",manufacturer:"RIM"},{regex:"(Black[bB]erry)\\s?(\\d+)",family_replacement:"Blackberry",manufacturer:"RIM"},{regex:"(OmniWeb)/v(\\d+)\\.(\\d+)",other:!0},{regex:"(Blazer)/(\\d+)\\.(\\d+)",family_replacement:"Palm Blazer",manufacturer:"Palm"},{regex:"(Pre)/(\\d+)\\.(\\d+)",family_replacement:"Palm Pre",manufacturer:"Palm"},{regex:"(Links) \\((\\d+)\\.(\\d+)",other:!0},{regex:"(QtWeb) Internet Browser/(\\d+)\\.(\\d+)",other:!0},{regex:"(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?",other:!0,tablet:!0},{regex:"(AppleWebKit)/(\\d+)\\.?(\\d+)?\\+ .* Version/\\d+\\.\\d+.\\d+ Safari/",family_replacement:"WebKit Nightly"},{regex:"(Version)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari/",family_replacement:"Safari"},{regex:"(Safari)/\\d+"},{regex:"(OLPC)/Update(\\d+)\\.(\\d+)",other:!0},{regex:"(OLPC)/Update()\\.(\\d+)",v1_replacement:"0",other:!0},{regex:"(SEMC\\-Browser)/(\\d+)\\.(\\d+)",other:!0},{regex:"(Teleca)",family_replacement:"Teleca Browser",other:!0},{regex:"Trident(.*)rv.(\\d+)\\.(\\d+)",family_replacement:"IE"},{regex:"(MSIE) (\\d+)\\.(\\d+)",family_replacement:"IE"}],os_parsers:[{regex:"(Android) (\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"},{regex:"(Android)\\-(\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"},{regex:"(Android) Donut",os_v2_replacement:"2",os_v1_replacement:"1"},{regex:"(Android) Eclair",os_v2_replacement:"1",os_v1_replacement:"2"},{regex:"(Android) Froyo",os_v2_replacement:"2",os_v1_replacement:"2"},{regex:"(Android) Gingerbread",os_v2_replacement:"3",os_v1_replacement:"2"},{regex:"(Android) Honeycomb",os_v1_replacement:"3"},{regex:"(Silk-Accelerated=[a-z]{4,5})",os_replacement:"Android"},{regex:"(Windows Phone 6\\.5)"},{regex:"(Windows (?:NT 5\\.2|NT 5\\.1))",os_replacement:"Windows XP"},{regex:"(XBLWP7)",os_replacement:"Windows Phone OS"},{regex:"(Windows NT 6\\.1)",os_replacement:"Windows 7"},{regex:"(Windows NT 6\\.0)",os_replacement:"Windows Vista"},{regex:"(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\\.0|Windows Vista|Windows 2000)"},{regex:"(Windows NT 6\\.4|Windows NT 10\\.0)",os_replacement:"Windows 10"},{regex:"(Windows NT 6\\.2)",os_replacement:"Windows 8"},{regex:"(Windows Phone 8)",os_replacement:"Windows Phone 8"},{regex:"(Windows NT 5\\.0)",os_replacement:"Windows 2000"},{regex:"(Windows Phone OS) (\\d+)\\.(\\d+)"},{regex:"(Windows ?Mobile)",os_replacement:"Windows Mobile"},{regex:"(WinNT4.0)",os_replacement:"Windows NT 4.0"},{regex:"(Win98)",os_replacement:"Windows 98"},{regex:"(Tizen)/(\\d+)\\.(\\d+)",other:!0},{regex:"(Mac OS X) (\\d+)[_.](\\d+)(?:[_.](\\d+))?",manufacturer:"Apple"},{regex:"(?:PPC|Intel) (Mac OS X)",manufacturer:"Apple"},{regex:"(CPU OS|iPhone OS) (\\d+)_(\\d+)(?:_(\\d+))?",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(iPhone|iPad|iPod); Opera",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(iPad); Opera",tablet:!0,manufacturer:"Apple"},{regex:"(iPhone|iPad|iPod).*Mac OS X.*Version/(\\d+)\\.(\\d+)",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(CrOS) [a-z0-9_]+ (\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"Chrome OS"},{regex:"(Debian)-(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",other:!0},{regex:"(Linux Mint)(?:/(\\d+))?",other:!0},{regex:"(Mandriva)(?: Linux)?/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",other:!0},{regex:"(Symbian[Oo][Ss])/(\\d+)\\.(\\d+)",os_replacement:"Symbian OS"},{regex:"(Symbian/3).+NokiaBrowser/7\\.3",os_replacement:"Symbian^3 Anna"},{regex:"(Symbian/3).+NokiaBrowser/7\\.4",os_replacement:"Symbian^3 Belle"},{regex:"(Symbian/3)",os_replacement:"Symbian^3"},{regex:"(Series 60|SymbOS|S60)",os_replacement:"Symbian OS"},{regex:"(MeeGo)",other:!0},{regex:"Symbian [Oo][Ss]",os_replacement:"Symbian OS"},{regex:"(Black[Bb]erry)[0-9a-z]+/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"BlackBerry OS",manufacturer:"RIM"},{regex:"(Black[Bb]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"BlackBerry OS",manufacturer:"RIM"},{regex:"(RIM Tablet OS) (\\d+)\\.(\\d+)\\.(\\d+)",os_replacement:"BlackBerry Tablet OS",tablet:!0,manufacturer:"RIM"},{regex:"(Play[Bb]ook)",os_replacement:"BlackBerry Tablet OS",tablet:!0,manufacturer:"RIM"},{regex:"(Black[Bb]erry)",os_replacement:"Blackberry OS",manufacturer:"RIM"},{regex:"(webOS|hpwOS)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"webOS"},{regex:"(SUSE|Fedora|Red Hat|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",other:!0},{regex:"(SUSE|Fedora|Red Hat|Puppy|PCLinuxOS|CentOS)/(\\d+)\\.(\\d+)\\.(\\d+)",other:!0},{regex:"(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\\d+)\\.(\\d+)"},{regex:"(Windows|OpenBSD|FreeBSD|NetBSD|Ubuntu|Kubuntu|Android|Arch Linux|CentOS|WeTab|Slackware)"},{regex:"(Linux|BSD)",other:!0}],mobile_os_families:["Windows Phone 6.5","Windows CE","Symbian OS"],device_parsers:[{regex:"HTC ([A-Z][a-z0-9]+) Build",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC ([A-Z][a-z0-9 ]+) \\d+\\.\\d+\\.\\d+\\.\\d+",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC_Touch_([A-Za-z0-9]+)",device_replacement:"HTC Touch ($1)",manufacturer:"HTC"},{regex:"USCCHTC(\\d+)",device_replacement:"HTC $1 (US Cellular)",manufacturer:"HTC"},{regex:"Sprint APA(9292)",device_replacement:"HTC $1 (Sprint)",manufacturer:"HTC"},{regex:"HTC ([A-Za-z0-9]+ [A-Z])",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC-([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC_([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC ([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"(ADR[A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"(HTC)",manufacturer:"HTC"},{regex:"SonyEricsson([A-Za-z0-9]+)/",device_replacement:"Ericsson $1",other:!0,manufacturer:"Sony"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; WOWMobile (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\-update1\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; (.+) Build"},{regex:"NokiaN([0-9]+)",device_replacement:"Nokia N$1",manufacturer:"Nokia"},{regex:"Nokia([A-Za-z0-9\\v-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"NOKIA ([A-Za-z0-9\\-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"Nokia ([A-Za-z0-9\\-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"Lumia ([A-Za-z0-9\\-]+)",device_replacement:"Lumia $1",manufacturer:"Nokia"},{regex:"Symbian",device_replacement:"Nokia",manufacturer:"Nokia"},{regex:"(PlayBook).+RIM Tablet OS",device_replacement:"Blackberry Playbook",tablet:!0,manufacturer:"RIM"},{regex:"(Black[Bb]erry [0-9]+);",manufacturer:"RIM"},{regex:"Black[Bb]erry([0-9]+)",device_replacement:"BlackBerry $1",manufacturer:"RIM"},{regex:"(Pre)/(\\d+)\\.(\\d+)",device_replacement:"Palm Pre",manufacturer:"Palm"},{regex:"(Pixi)/(\\d+)\\.(\\d+)",device_replacement:"Palm Pixi",manufacturer:"Palm"},{regex:"(Touchpad)/(\\d+)\\.(\\d+)",device_replacement:"HP Touchpad",manufacturer:"HP"},{regex:"HPiPAQ([A-Za-z0-9]+)/(\\d+).(\\d+)",device_replacement:"HP iPAQ $1",manufacturer:"HP"},{regex:"Palm([A-Za-z0-9]+)",device_replacement:"Palm $1",manufacturer:"Palm"},{regex:"Treo([A-Za-z0-9]+)",device_replacement:"Palm Treo $1",manufacturer:"Palm"},{regex:"webOS.*(P160UNA)/(\\d+).(\\d+)",device_replacement:"HP Veer",manufacturer:"HP"},{regex:"(Kindle Fire)",manufacturer:"Amazon"},{regex:"(Kindle)",manufacturer:"Amazon"},{regex:"(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?",device_replacement:"Kindle Fire",tablet:!0,manufacturer:"Amazon"},{regex:"(iPad) Simulator;",manufacturer:"Apple"},{regex:"(iPad);",manufacturer:"Apple"},{regex:"(iPod);",manufacturer:"Apple"},{regex:"(iPhone) Simulator;",manufacturer:"Apple"},{regex:"(iPhone);",manufacturer:"Apple"},{regex:"Nexus\\ ([A-Za-z0-9\\-]+)",device_replacement:"Nexus $1"},{regex:"acer_([A-Za-z0-9]+)_",device_replacement:"Acer $1",manufacturer:"Acer"},{regex:"acer_([A-Za-z0-9]+)_",device_replacement:"Acer $1",manufacturer:"Acer"},{regex:"Amoi\\-([A-Za-z0-9]+)",device_replacement:"Amoi $1",other:!0,manufacturer:"Amoi"},{regex:"AMOI\\-([A-Za-z0-9]+)",device_replacement:"Amoi $1",other:!0,manufacturer:"Amoi"},{regex:"Asus\\-([A-Za-z0-9]+)",device_replacement:"Asus $1",manufacturer:"Asus"},{regex:"ASUS\\-([A-Za-z0-9]+)",device_replacement:"Asus $1",manufacturer:"Asus"},{regex:"BIRD\\-([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"BIRD\\.([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"BIRD ([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"Dell ([A-Za-z0-9]+)",device_replacement:"Dell $1",manufacturer:"Dell"},{regex:"DoCoMo/2\\.0 ([A-Za-z0-9]+)",device_replacement:"DoCoMo $1",other:!0},{regex:"([A-Za-z0-9]+)\\_W\\;FOMA",device_replacement:"DoCoMo $1",other:!0},{regex:"([A-Za-z0-9]+)\\;FOMA",device_replacement:"DoCoMo $1",other:!0},{regex:"vodafone([A-Za-z0-9]+)",device_replacement:"Huawei Vodafone $1",other:!0},{regex:"i\\-mate ([A-Za-z0-9]+)",device_replacement:"i-mate $1",other:!0},{regex:"Kyocera\\-([A-Za-z0-9]+)",device_replacement:"Kyocera $1",other:!0},{regex:"KWC\\-([A-Za-z0-9]+)",device_replacement:"Kyocera $1",other:!0},{regex:"Lenovo\\-([A-Za-z0-9]+)",device_replacement:"Lenovo $1",manufacturer:"Lenovo"},{regex:"Lenovo\\_([A-Za-z0-9]+)",device_replacement:"Lenovo $1",manufacturer:"Levovo"},{regex:"LG/([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG-LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE-LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE VX([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG ([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE LG\\-AX([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG\\-([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE\\-([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"(KIN)\\.One (\\d+)\\.(\\d+)",device_replacement:"Microsoft $1"},{regex:"(KIN)\\.Two (\\d+)\\.(\\d+)",device_replacement:"Microsoft $1"},{regex:"(Motorola)\\-([A-Za-z0-9]+)",manufacturer:"Motorola"},{regex:"MOTO\\-([A-Za-z0-9]+)",device_replacement:"Motorola $1",manufacturer:"Motorola"},{regex:"MOT\\-([A-Za-z0-9]+)",device_replacement:"Motorola $1",manufacturer:"Motorola"},{regex:"Philips([A-Za-z0-9]+)",device_replacement:"Philips $1",manufacturer:"Philips"},{regex:"Philips ([A-Za-z0-9]+)",device_replacement:"Philips $1",manufacturer:"Philips"},{regex:"SAMSUNG-([A-Za-z0-9\\-]+)",device_replacement:"Samsung $1",manufacturer:"Samsung"},{regex:"SAMSUNG\\; ([A-Za-z0-9\\-]+)",device_replacement:"Samsung $1",manufacturer:"Samsung"},{regex:"Softbank/1\\.0/([A-Za-z0-9]+)",device_replacement:"Softbank $1",other:!0},{regex:"Softbank/2\\.0/([A-Za-z0-9]+)",device_replacement:"Softbank $1",other:!0},{regex:"(hiptop|avantgo|plucker|xiino|blazer|elaine|up.browser|up.link|mmp|smartphone|midp|wap|vodafone|o2|pocket|mobile|pda)",device_replacement:"Generic Smartphone"},{regex:"^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\\-|airn|alav|asus|attw|au\\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\\-n|bw\\-u|beck|benq|bilb|blac|c55/|cdm\\-|chtm|capi|comp|cond|craw|dall|dbte|dc\\-s|dica|ds\\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\\-|fly\\_|g\\-mo|g1 u|g560|gf\\-5|grun|gene|go.w|good|grad|hcit|hd\\-m|hd\\-p|hd\\-t|hei\\-|hp i|hpip|hs\\-c|htc |htc\\-|htca|htcg)",device_replacement:"Generic Feature Phone"},{regex:"^(htcp|htcs|htct|htc\\_|haie|hita|huaw|hutc|i\\-20|i\\-go|i\\-ma|i230|iac|iac\\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\\-|klon|lexi|lg g|lg\\-a|lg\\-b|lg\\-c|lg\\-d|lg\\-f|lg\\-g|lg\\-k|lg\\-l|lg\\-m|lg\\-o|lg\\-p|lg\\-s|lg\\-t|lg\\-u|lg\\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\\-|lge/|lynx|leno|m1\\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\\-|nem\\-|newg|neon)",device_replacement:"Generic Feature Phone"},{regex:"^(netf|noki|nzph|o2 x|o2\\-x|opwv|owg1|opti|oran|ot\\-s|p800|pand|pg\\-1|pg\\-2|pg\\-3|pg\\-6|pg\\-8|pg\\-c|pg13|phil|pn\\-2|pt\\-g|palm|pana|pire|pock|pose|psio|qa\\-a|qc\\-2|qc\\-3|qc\\-5|qc\\-7|qc07|qc12|qc21|qc32|qc60|qci\\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\\-|scp\\-|sdk/|se47|sec\\-|sec0|sec1|semc|sgh\\-|shar|sie\\-|sk\\-0|sl45|slid|smb3|smt5|sp01|sph\\-|spv |spv\\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\\-mo|t218|t250|t600|t610|t618|tcl\\-|tdg\\-|telm|tim\\-|ts70|tsm\\-|tsm3|tsm5|tx\\-9|tagt)",device_replacement:"Generic Feature Phone"},{regex:"^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\\-|your|zte\\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\\-|webc|whit|wmlb|xda\\-|xda\\_)",device_replacement:"Generic Feature Phone"},{regex:"(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\\-webcrawler|converacrawler|dataparksearch|findlinks)",device_replacement:"Spider"}],mobile_browser_families:["Firefox Mobile","Opera Mobile","Opera Mini","Mobile Safari","webOS","IE Mobile","Playstation Portable","Nokia","Blackberry","Palm","Silk","Android","Maemo","Obigo","Netfront","AvantGo","Teleca","SEMC-Browser","Bolt","Iris","UP.Browser","Symphony","Minimo","Bunjaloo","Jasmine","Dolfin","Polaris","BREW","Chrome Mobile","Chrome Mobile iOS","UC Browser","Tizen Browser"]};a.parsers=["device_parsers","browser_parsers","os_parsers","mobile_os_families","mobile_browser_families"],a.types=["browser","os","device"],a.regexes=b||function(){var b={};return a.parsers.map(function(a){b[a]=[]}),b}(),a.families=function(){var b={};return a.types.map(function(a){b[a]=[]}),b}();var c=Array.prototype,d=(Object.prototype,Function.prototype,c.forEach);c.indexOf;var e=function(a,b){for(var c={},d=0;b.length>d&&!(c=b[d](a));d++);return c},f=function(a,b){g(a,function(a){g(b,function(b){delete a[b]})})},g=forEach=function(a,b,c){if(null!=a)if(d&&a.forEach===d)a.forEach(b,c);else if(a.length===+a.length)for(var e=0,f=a.length;f>e;e++)b.call(c,a[e],e,a);else for(var g in a)_.has(a,g)&&b.call(c,a[g],g,a)},h=function(a){return!(!a||void 0===a||null==a)},i=function(a){var b="";return a=a||{},h(a)&&h(a.major)&&(b+=a.major,h(a.minor)&&(b+="."+a.minor,h(a.patch)&&(b+="."+a.patch))),b},j=function(a){a=a||{};var b=i(a);return b&&(b=" "+b),a&&h(a.family)?a.family+b:""};return a.parse=function(b){var c=function(b){return a.regexes[b+"_parsers"].map(function(a){function c(b){var c=b.match(d);if(!c)return null;var g={};return g.family=(e?e.replace("$1",c[1]):c[1])||"other",g.major=parseInt(f?f:c[2])||null,g.minor=c[3]?parseInt(c[3]):null,g.patch=c[4]?parseInt(c[4]):null,g.tablet=a.tablet,g.man=a.manufacturer||null,g}var d=RegExp(a.regex),e=a[("browser"===b?"family":b)+"_replacement"],f=a.major_version_replacement;return c})},d=function(){},g=c("browser"),k=c("os"),l=c("device"),m=new d;m.source=b,m.browser=e(b,g),h(m.browser)?(m.browser.name=j(m.browser),m.browser.version=i(m.browser)):m.browser={},m.os=e(b,k),h(m.os)?(m.os.name=j(m.os),m.os.version=i(m.os)):m.os={},m.device=e(b,l),h(m.device)?(m.device.name=j(m.device),m.device.version=i(m.device)):m.device={tablet:!1,family:"Other"};var n={};return a.regexes.mobile_browser_families.map(function(a){n[a]=!0}),a.regexes.mobile_os_families.map(function(a){n[a]=!0}),m.device.type="Spider"===m.browser.family?"Spider":m.browser.tablet||m.os.tablet||m.device.tablet?"Tablet":n.hasOwnProperty(m.browser.family)?"Mobile":"Desktop",m.device.manufacturer=m.browser.man||m.os.man||m.device.man||null,f([m.browser,m.os,m.device],["tablet","man"]),m},a}();"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=b),exports.detect=b):a.detect=b,"function"==typeof define&&define.amd&&define(function(){return b})}(window),function(){"use strict";var a=function(a,b,c){a.hasOwnProperty(b)?console.warn("Property already exist"):a[b]=c};amp.viewerSettings={viewerConfigs:{v:"1.1.3",target:"#amp-container",client:"playground",imageBasePath:"//i1.adis.ws/",errImg:"404",errCallback:function(){},cacheControl:1,cacheWindow:315569259747,fullNavHeight:100,templates:{thumb:"w=85&h=85&qlt=70",desktop:{main:"w=1000&h=1000",mainRetina:"w=2000&h=2000"},desktopFull:{main:"w=1000",mainRetina:"w=2000"},mobile:{main:"w=500&h=500",mainRetina:"w=1000&h=1000"}},tooltips:{offsets:{left:-102,top:-39},displayTime:3e3,desktop:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}},desktopFull:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}},mobile:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}}},navIconsMain:{next:"icon icon-right bla-main-next",prev:"icon icon-left bla-main-prev"},navIconsNav:{next:"icon icon-right bla-nav-next",prev:"icon icon-left bla-nav-prev"},navIconsPortraitNav:{next:"icon icon-right bla-portrait-next",prev:"icon icon-left bla-portrait-prev"},zoomInlineDoubleTap:!0,doubleTapTime:250,ampConfigs:{navElementsWidthPx:100,navElementsWidthPxMobile:50,navElementsCount:{forDesktop:5,forDesktopFull:4},mainContainerCarousel:{width:1,height:1,responsive:!0,start:1,loop:!1,dir:"horz",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"horz",distance:100},animDuration:200,layout:"standard",onActivate:{select:!0,goTo:!0},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0},mainContainerNav:{on:"goTo",action:"select",selector:".nav-container .list"},mainContainerSpin:{width:1,height:1,responsive:!0,delay:100,autoplay:!1,gesture:{enabled:!0,fingers:1},loop:!0,start:1,momentum:!0,minDistance:50,friction:.97,dragDistance:200,preload:"created",preloadType:"full",activate:"down",dir:"normal",cursor:{active:"pointer",inactive:"pointer"},play:{onLoad:!0,onVisible:!0,repeat:1,delay:600},lazyLoad:!1,orientation:"horz"},mainContainerSpin3d:{loop:!1,dragDistance:200,orientation:"vert",preload:"created",preloadType:"window",width:1,height:1,gesture:{enabled:!0,fingers:1}},mainContainerVideo:{width:1,height:1,center:!0,responsive:!0,autoplay:!1,loop:!1,muted:!1,controls:!0,pauseOnHide:!0,nativeControlsForTouch:!1,plugins:{videoJsResolutionSwitcher:{default:"Medium"}}},mainContainerZoomInline:{transforms:[],scaleMax:3,scaleStep:.5,scaleSteps:!0,pinch:!0,pan:!0,events:{zoomIn:"",zoomOut:"",move:""},activation:{inGesture:!0},preload:!1,preventVisibleZoomOut:!0},navContainerCarousel:{height:1,responsive:!0,start:1,loop:!1,dir:"horz",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"horz",distance:50},animDuration:200,layout:"standard",onActivate:{select:!0,goTo:!1},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0},navContainerNav:{on:"select",action:"select",selector:".main-container .list"},image:{preload:"created",insertAfter:!1,errImg:null}}},portraitConfigs:function(){var b=this;a(b.viewerConfigs.ampConfigs,"navContainerCarouselPortrait",{height:"100%",responsive:!0,start:1,loop:!1,dir:"vert",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"vert",distance:50},animDuration:500,layout:"standard",onActivate:{select:!0,goTo:!1},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0}),a(b.viewerConfigs.ampConfigs,"mainContainerSpinPortrait",{height:"100%",responsive:!0,delay:100,autoplay:!1,gesture:{enabled:!0,fingers:1},loop:!0,start:1,momentum:!0,minDistance:50,friction:.97,dragDistance:200,preload:"created",preloadType:"full",activate:"down",dir:"normal",cursor:{active:"pointer",inactive:"pointer"},play:{onLoad:!0,onVisible:!0,repeat:1},lazyLoad:!1,orientation:"horz"}),a(b.viewerConfigs.ampConfigs,"mainContainerVideoPortrait",{height:"100%",responsive:!0,autoplay:!1,loop:!1,muted:!1,controls:!0,pauseOnHide:!0,nativeControlsForTouch:!0,plugins:{videoJsResolutionSwitcher:!0}})},overwritePortraitSettings:function(a){a.ampConfigs.mainContainerCarousel.width=.8,a.ampConfigs.mainContainerCarousel.height=1.2,a.templates={thumb:"w=85&h=85&qlt=70",thumbPortrait:"w=67&h=89&qlt=100",desktop:{main:"w=1010&h=1416",mainRetina:"w=2020&h=2832"},desktopFull:{main:"w=1010&h=1416",mainRetina:"w=2020&h=2832"},mobile:{main:"w=505&h=708",mainRetina:"w=1010&h=1416"}}}}}(),function(a,b){"use strict";var c="Amplience Viewer",d=function(c){var d=this,e=amp.viewerSettings.viewerConfigs;"portrait"===c.view?(amp.viewerSettings.overwritePortraitSettings(e),amp.viewerSettings.portraitConfigs(),d.isPortraitView=!0):"landscape"===c.view?d.isLandscapeView=!0:d.isSquareView=!0,d.settings=b.extend(!0,{},e,c),d.listVisible=d.settings.ampConfigs.mainContainerCarousel.listVisible,("number"!=typeof d.listVisible||d.listVisible<1)&&(d.listVisible=1),d.settings.locale&&d.settings.locale.length>0&&d.settings.ampConfigs.mainContainerZoomInline.transforms.push("locale="+d.settings.locale),d.views={desktopNormalView:"desktopNormalView",desktopFullView:"desktopFullView",mobileNormalView:"mobileNormalView"},d.assets=[],d.currentAssetIndex=0,d.canTouch=!!("ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),d.wrapper=b('
    '),d.deviceWidth=a.innerWidth,d.controller(),d.tags=[],d.IE=d.isIE(),d.tooltipsTimeout=[]};d.prototype.controller=function(){var a=this;amp.init({client_id:a.settings.client,di_basepath:a.settings.imageBasePath,cache_window:a.settings.cacheWindow}),window.ecommBridge&&a.settings.ecommBridge&&this.bridgeConnector.initAll(),a.applyImgTemplates(),b(a.settings.target).append(a.wrapper);var d=a.initSetData();a.getSet(d).then(function(b){a.assets=b,a.renderInitialView()}).catch(function(a){console.warn(a,c+" unable to get set list.")})},d.prototype.initSetData=function(){var a=this,b=a.bridgeConnector.page;return null!==b&&a.settings.ecommBridge?b.mediaList&&b.mediaList.constructor===Array&&b.mediaList.length>0?a.returnSetData(b.mediaList):b.mediaSet&&"string"==typeof b.mediaSet&&b.mediaSet.length>0?a.returnSetData(b.mediaSet):void 0:a.returnSetData(a.settings.set)},d.prototype.returnSetData=function(a){var b=this,c="&v="+b.settings.cacheControl;return a.constructor===Array?(b.bridgeConnector.enrichMediaListWithParams(a,{transform:c}),a):{name:a,type:"s",transform:c}},d.prototype.secureData=function(a){if(this.settings.secure){var b=JSON.stringify(a);b=b.replace(/http:\/\//g,"https://"),a=JSON.parse(b)}return a},d.prototype.getSet=function(a){var b=this;return new Promise(function(c,d){amp.get(a,function(d){var e=null;e=a.constructor===Array?b.bridgeConnector.convertListToSet(a,d).items:d[a.name].items,c(e)},function(){b.getImage(b.settings.errImg).then(function(a){b.settings.errCallback.call(b),c([{src:a.url}])})},!1,!1,b.secureData.bind(b))})},d.prototype.getImage=function(a){var b=this;return new Promise(function(c,d){amp.get({name:a,type:"i",transform:"&v="+b.settings.cacheControl},function(b){c(b[a])},function(){c({url:"//i1.adis.ws/i/playground/404"})},!1,!1,b.secureData.bind(b))})},d.prototype.changeSet=function(a){var b=this;null!==b.bridgeConnector.page&&b.settings.ecommBridge?a.constructor===Array&&a.length>0?b.bridgeConnector.page.mediaList=a:"string"==typeof a&&a.length>0&&(b.bridgeConnector.page.mediaset=a,b.bridgeConnector.page.mediaList=null):b.settings.set=a;var d=b.returnSetData(a);b.getSet(d).then(function(a){b.assets=a,b.currentAssetIndex=0,b.renderInitialView()}).catch(function(a){console.warn(a,c+" unable to get set list.")})},d.prototype.isIE=function(){return !!/MSIE [0-9]{1,}/.test(navigator.userAgent)||!(!/Trident\/\d./i.test(navigator.userAgent)&&!/Edge\/\d./i.test(navigator.userAgent));},d.prototype.isMobile=function(){return!!this.settings.isMobile||a.innerWidth<=768},d.prototype.renderInitialView=function(){var a=this;a.currentView=a.isMobile()?a.views.mobileNormalView:a.views.desktopNormalView,a.renderView(a.currentView)},d.prototype.renderView=function(a,d){var e=this,d=d||!1;switch(e.destroyAmpWidgets(),a){case e.views.desktopNormalView:e.renderDesktopNormalView();break;case e.views.desktopFullView:e.renderDesktopFullView();break;case e.views.mobileNormalView:e.renderMobileNormalView();break;default:console.warn(c+": Unknown view: "+a+". Viewer desktopNormalView."),e.renderDesktopNormalView()}switch(a===e.views.desktopFullView?(this._scrollPosition=b(window).scrollTop(),b("html, body").addClass("amp-no-scroll")):(b("html, body").removeClass("amp-no-scroll"),b(window).scrollTop(this._scrollPosition)),e.mainContainerList=e.wrapper.find(".main-container .list"),e.slides=!1,e.navContainerList=e.wrapper.find(".nav-container .list"),e.tooltips=e.wrapper.find(".main-container .tooltip"),e.tooltipsText=e.tooltips.find("span.text"),e.bindGenericEvents(),e.bindAmpEvents(),e.bindNavigationEvents(),e.bindSpinEvents(),e.initImagesSrcset(),e.initAmpWidgets(d),e.applyNavigationStyles(),e.checkMainContainerNavArrows(),e.checkNavContainerNavArrows(),e.checkZoomIcons(),e.checkMainContainerSlidesVisibility(),a){case e.views.desktopNormalView:e.bindDesktopNormalViewEvents();break;case e.views.desktopFullView:e.bindDesktopFullViewEvents();break;case e.views.mobileNormalView:e.bindMobileNormalViewEvents()}e.settings.initCallback&&e.settings.initCallback.apply(e)},d.prototype.getTemplateData=function(a){var c=this,d={items:c.assets,templates:c.getTemplates(),locale:{first:"",second:""},view:""};if(c.settings.locale&&b.trim(c.settings.locale).length>0){var e="locale="+c.settings.locale;d.locale.first="?"+e,d.locale.second="&"+e}return c.settings.view&&c.settings.view.length>0&&(d.view=c.settings.view),d},d.prototype.renderDesktopNormalView=function(){var a=this;a.currentView=a.views.desktopNormalView,a.wrapper.html(amp.templates.desktopNormalView(a.getTemplateData())),a.cloneTooltip(a.listVisible)},d.prototype.cloneTooltip=function(a){for(var b=this.wrapper.find(".main-container .tooltip"),c=1;c0)i.ampSpin(d.mainContainerSpin3d),j.each(function(a){var c=b.extend(!0,{},d.mainContainerSpin,{play:{onVisible:!1,onLoad:!1},preloadType:"window"});b(this).ampSpin(c)});else{var k=d.mainContainerSpin;1==k.play.onVisible&&(c.spinVisible=!0,k.play.onVisible=!1),i.ampSpin(k)}}else if(h.hasOwnProperty("media")){var l=d.mainContainerVideo;c.settings.view&&c.isPortraitView&&c.currentView===c.views.desktopNormalView&&(l=d.mainContainerVideoPortrait,l.nativeControlsForTouch=!1);var m=c.mainContainerList.find("#"+h.name).ampVideo(l);m.find("video").on("touchstart",function(){2==m.ampVideo("state")?m.ampVideo("play"):m.ampVideo("pause")}), +family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPhone)",family_replacement:"Mobile Safari",manufacturer:"Apple"},{regex:"(iPad).*Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(iPad).*Version/(\\d+)\\.(\\d+)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(iPad)",family_replacement:"Mobile Safari",tablet:!0,manufacturer:"Apple"},{regex:"(AvantGo) (\\d+).(\\d+)",other:!0},{regex:"(Avant)",v1_replacement:"1",other:!0},{regex:"^(Nokia)",family_replacement:"Nokia Services (WAP) Browser",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)\\.(\\d+)",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)",manufacturer:"Nokia"},{regex:"(NokiaBrowser)/(\\d+)\\.(\\d+)",manufacturer:"Nokia"},{regex:"(BrowserNG)/(\\d+)\\.(\\d+).(\\d+)",family_replacement:"NokiaBrowser",manufacturer:"Nokia"},{regex:"(Series60)/5\\.0",v2_replacement:"0",v1_replacement:"7",family_replacement:"NokiaBrowser",manufacturer:"Nokia"},{regex:"(Series60)/(\\d+)\\.(\\d+)",family_replacement:"Nokia OSS Browser",manufacturer:"Nokia"},{regex:"(S40OviBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Nokia Series 40 Ovi Browser",manufacturer:"Nokia"},{regex:"(Nokia)[EN]?(\\d+)",manufacturer:"Nokia"},{regex:"(PlayBook).+RIM Tablet OS (\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Blackberry WebKit",tablet:!0,manufacturer:"Nokia"},{regex:"(Black[bB]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)",family_replacement:"Blackberry WebKit",manufacturer:"RIM"},{regex:"(Black[bB]erry)\\s?(\\d+)",family_replacement:"Blackberry",manufacturer:"RIM"},{regex:"(OmniWeb)/v(\\d+)\\.(\\d+)",other:!0},{regex:"(Blazer)/(\\d+)\\.(\\d+)",family_replacement:"Palm Blazer",manufacturer:"Palm"},{regex:"(Pre)/(\\d+)\\.(\\d+)",family_replacement:"Palm Pre",manufacturer:"Palm"},{regex:"(Links) \\((\\d+)\\.(\\d+)",other:!0},{regex:"(QtWeb) Internet Browser/(\\d+)\\.(\\d+)",other:!0},{regex:"(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?",other:!0,tablet:!0},{regex:"(AppleWebKit)/(\\d+)\\.?(\\d+)?\\+ .* Version/\\d+\\.\\d+.\\d+ Safari/",family_replacement:"WebKit Nightly"},{regex:"(Version)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari/",family_replacement:"Safari"},{regex:"(Safari)/\\d+"},{regex:"(OLPC)/Update(\\d+)\\.(\\d+)",other:!0},{regex:"(OLPC)/Update()\\.(\\d+)",v1_replacement:"0",other:!0},{regex:"(SEMC\\-Browser)/(\\d+)\\.(\\d+)",other:!0},{regex:"(Teleca)",family_replacement:"Teleca Browser",other:!0},{regex:"Trident(.*)rv.(\\d+)\\.(\\d+)",family_replacement:"IE"},{regex:"(MSIE) (\\d+)\\.(\\d+)",family_replacement:"IE"}],os_parsers:[{regex:"(Android) (\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"},{regex:"(Android)\\-(\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"},{regex:"(Android) Donut",os_v2_replacement:"2",os_v1_replacement:"1"},{regex:"(Android) Eclair",os_v2_replacement:"1",os_v1_replacement:"2"},{regex:"(Android) Froyo",os_v2_replacement:"2",os_v1_replacement:"2"},{regex:"(Android) Gingerbread",os_v2_replacement:"3",os_v1_replacement:"2"},{regex:"(Android) Honeycomb",os_v1_replacement:"3"},{regex:"(Silk-Accelerated=[a-z]{4,5})",os_replacement:"Android"},{regex:"(Windows Phone 6\\.5)"},{regex:"(Windows (?:NT 5\\.2|NT 5\\.1))",os_replacement:"Windows XP"},{regex:"(XBLWP7)",os_replacement:"Windows Phone OS"},{regex:"(Windows NT 6\\.1)",os_replacement:"Windows 7"},{regex:"(Windows NT 6\\.0)",os_replacement:"Windows Vista"},{regex:"(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\\.0|Windows Vista|Windows 2000)"},{regex:"(Windows NT 6\\.4|Windows NT 10\\.0)",os_replacement:"Windows 10"},{regex:"(Windows NT 6\\.2)",os_replacement:"Windows 8"},{regex:"(Windows Phone 8)",os_replacement:"Windows Phone 8"},{regex:"(Windows NT 5\\.0)",os_replacement:"Windows 2000"},{regex:"(Windows Phone OS) (\\d+)\\.(\\d+)"},{regex:"(Windows ?Mobile)",os_replacement:"Windows Mobile"},{regex:"(WinNT4.0)",os_replacement:"Windows NT 4.0"},{regex:"(Win98)",os_replacement:"Windows 98"},{regex:"(Tizen)/(\\d+)\\.(\\d+)",other:!0},{regex:"(Mac OS X) (\\d+)[_.](\\d+)(?:[_.](\\d+))?",manufacturer:"Apple"},{regex:"(?:PPC|Intel) (Mac OS X)",manufacturer:"Apple"},{regex:"(CPU OS|iPhone OS) (\\d+)_(\\d+)(?:_(\\d+))?",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(iPhone|iPad|iPod); Opera",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(iPad); Opera",tablet:!0,manufacturer:"Apple"},{regex:"(iPhone|iPad|iPod).*Mac OS X.*Version/(\\d+)\\.(\\d+)",os_replacement:"iOS",manufacturer:"Apple"},{regex:"(CrOS) [a-z0-9_]+ (\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"Chrome OS"},{regex:"(Debian)-(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",other:!0},{regex:"(Linux Mint)(?:/(\\d+))?",other:!0},{regex:"(Mandriva)(?: Linux)?/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",other:!0},{regex:"(Symbian[Oo][Ss])/(\\d+)\\.(\\d+)",os_replacement:"Symbian OS"},{regex:"(Symbian/3).+NokiaBrowser/7\\.3",os_replacement:"Symbian^3 Anna"},{regex:"(Symbian/3).+NokiaBrowser/7\\.4",os_replacement:"Symbian^3 Belle"},{regex:"(Symbian/3)",os_replacement:"Symbian^3"},{regex:"(Series 60|SymbOS|S60)",os_replacement:"Symbian OS"},{regex:"(MeeGo)",other:!0},{regex:"Symbian [Oo][Ss]",os_replacement:"Symbian OS"},{regex:"(Black[Bb]erry)[0-9a-z]+/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"BlackBerry OS",manufacturer:"RIM"},{regex:"(Black[Bb]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"BlackBerry OS",manufacturer:"RIM"},{regex:"(RIM Tablet OS) (\\d+)\\.(\\d+)\\.(\\d+)",os_replacement:"BlackBerry Tablet OS",tablet:!0,manufacturer:"RIM"},{regex:"(Play[Bb]ook)",os_replacement:"BlackBerry Tablet OS",tablet:!0,manufacturer:"RIM"},{regex:"(Black[Bb]erry)",os_replacement:"Blackberry OS",manufacturer:"RIM"},{regex:"(webOS|hpwOS)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?",os_replacement:"webOS"},{regex:"(SUSE|Fedora|Red Hat|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)",other:!0},{regex:"(SUSE|Fedora|Red Hat|Puppy|PCLinuxOS|CentOS)/(\\d+)\\.(\\d+)\\.(\\d+)",other:!0},{regex:"(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\\d+)\\.(\\d+)"},{regex:"(Windows|OpenBSD|FreeBSD|NetBSD|Ubuntu|Kubuntu|Android|Arch Linux|CentOS|WeTab|Slackware)"},{regex:"(Linux|BSD)",other:!0}],mobile_os_families:["Windows Phone 6.5","Windows CE","Symbian OS"],device_parsers:[{regex:"HTC ([A-Z][a-z0-9]+) Build",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC ([A-Z][a-z0-9 ]+) \\d+\\.\\d+\\.\\d+\\.\\d+",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC_Touch_([A-Za-z0-9]+)",device_replacement:"HTC Touch ($1)",manufacturer:"HTC"},{regex:"USCCHTC(\\d+)",device_replacement:"HTC $1 (US Cellular)",manufacturer:"HTC"},{regex:"Sprint APA(9292)",device_replacement:"HTC $1 (Sprint)",manufacturer:"HTC"},{regex:"HTC ([A-Za-z0-9]+ [A-Z])",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC-([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC_([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"HTC ([A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"(ADR[A-Za-z0-9]+)",device_replacement:"HTC $1",manufacturer:"HTC"},{regex:"(HTC)",manufacturer:"HTC"},{regex:"SonyEricsson([A-Za-z0-9]+)/",device_replacement:"Ericsson $1",other:!0,manufacturer:"Sony"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; WOWMobile (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\-update1\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\; [A-Za-z]{2}\\-[A-Za-z]{2}\\; (.+) Build"},{regex:"Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; (.+) Build"},{regex:"NokiaN([0-9]+)",device_replacement:"Nokia N$1",manufacturer:"Nokia"},{regex:"Nokia([A-Za-z0-9\\v-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"NOKIA ([A-Za-z0-9\\-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"Nokia ([A-Za-z0-9\\-]+)",device_replacement:"Nokia $1",manufacturer:"Nokia"},{regex:"Lumia ([A-Za-z0-9\\-]+)",device_replacement:"Lumia $1",manufacturer:"Nokia"},{regex:"Symbian",device_replacement:"Nokia",manufacturer:"Nokia"},{regex:"(PlayBook).+RIM Tablet OS",device_replacement:"Blackberry Playbook",tablet:!0,manufacturer:"RIM"},{regex:"(Black[Bb]erry [0-9]+);",manufacturer:"RIM"},{regex:"Black[Bb]erry([0-9]+)",device_replacement:"BlackBerry $1",manufacturer:"RIM"},{regex:"(Pre)/(\\d+)\\.(\\d+)",device_replacement:"Palm Pre",manufacturer:"Palm"},{regex:"(Pixi)/(\\d+)\\.(\\d+)",device_replacement:"Palm Pixi",manufacturer:"Palm"},{regex:"(Touchpad)/(\\d+)\\.(\\d+)",device_replacement:"HP Touchpad",manufacturer:"HP"},{regex:"HPiPAQ([A-Za-z0-9]+)/(\\d+).(\\d+)",device_replacement:"HP iPAQ $1",manufacturer:"HP"},{regex:"Palm([A-Za-z0-9]+)",device_replacement:"Palm $1",manufacturer:"Palm"},{regex:"Treo([A-Za-z0-9]+)",device_replacement:"Palm Treo $1",manufacturer:"Palm"},{regex:"webOS.*(P160UNA)/(\\d+).(\\d+)",device_replacement:"HP Veer",manufacturer:"HP"},{regex:"(Kindle Fire)",manufacturer:"Amazon"},{regex:"(Kindle)",manufacturer:"Amazon"},{regex:"(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?",device_replacement:"Kindle Fire",tablet:!0,manufacturer:"Amazon"},{regex:"(iPad) Simulator;",manufacturer:"Apple"},{regex:"(iPad);",manufacturer:"Apple"},{regex:"(iPod);",manufacturer:"Apple"},{regex:"(iPhone) Simulator;",manufacturer:"Apple"},{regex:"(iPhone);",manufacturer:"Apple"},{regex:"Nexus\\ ([A-Za-z0-9\\-]+)",device_replacement:"Nexus $1"},{regex:"acer_([A-Za-z0-9]+)_",device_replacement:"Acer $1",manufacturer:"Acer"},{regex:"acer_([A-Za-z0-9]+)_",device_replacement:"Acer $1",manufacturer:"Acer"},{regex:"Amoi\\-([A-Za-z0-9]+)",device_replacement:"Amoi $1",other:!0,manufacturer:"Amoi"},{regex:"AMOI\\-([A-Za-z0-9]+)",device_replacement:"Amoi $1",other:!0,manufacturer:"Amoi"},{regex:"Asus\\-([A-Za-z0-9]+)",device_replacement:"Asus $1",manufacturer:"Asus"},{regex:"ASUS\\-([A-Za-z0-9]+)",device_replacement:"Asus $1",manufacturer:"Asus"},{regex:"BIRD\\-([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"BIRD\\.([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"BIRD ([A-Za-z0-9]+)",device_replacement:"Bird $1",other:!0},{regex:"Dell ([A-Za-z0-9]+)",device_replacement:"Dell $1",manufacturer:"Dell"},{regex:"DoCoMo/2\\.0 ([A-Za-z0-9]+)",device_replacement:"DoCoMo $1",other:!0},{regex:"([A-Za-z0-9]+)\\_W\\;FOMA",device_replacement:"DoCoMo $1",other:!0},{regex:"([A-Za-z0-9]+)\\;FOMA",device_replacement:"DoCoMo $1",other:!0},{regex:"vodafone([A-Za-z0-9]+)",device_replacement:"Huawei Vodafone $1",other:!0},{regex:"i\\-mate ([A-Za-z0-9]+)",device_replacement:"i-mate $1",other:!0},{regex:"Kyocera\\-([A-Za-z0-9]+)",device_replacement:"Kyocera $1",other:!0},{regex:"KWC\\-([A-Za-z0-9]+)",device_replacement:"Kyocera $1",other:!0},{regex:"Lenovo\\-([A-Za-z0-9]+)",device_replacement:"Lenovo $1",manufacturer:"Lenovo"},{regex:"Lenovo\\_([A-Za-z0-9]+)",device_replacement:"Lenovo $1",manufacturer:"Levovo"},{regex:"LG/([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG-LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE-LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE VX([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG ([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE LG\\-AX([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG\\-([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LGE\\-([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"LG([A-Za-z0-9]+)",device_replacement:"LG $1",manufacturer:"LG"},{regex:"(KIN)\\.One (\\d+)\\.(\\d+)",device_replacement:"Microsoft $1"},{regex:"(KIN)\\.Two (\\d+)\\.(\\d+)",device_replacement:"Microsoft $1"},{regex:"(Motorola)\\-([A-Za-z0-9]+)",manufacturer:"Motorola"},{regex:"MOTO\\-([A-Za-z0-9]+)",device_replacement:"Motorola $1",manufacturer:"Motorola"},{regex:"MOT\\-([A-Za-z0-9]+)",device_replacement:"Motorola $1",manufacturer:"Motorola"},{regex:"Philips([A-Za-z0-9]+)",device_replacement:"Philips $1",manufacturer:"Philips"},{regex:"Philips ([A-Za-z0-9]+)",device_replacement:"Philips $1",manufacturer:"Philips"},{regex:"SAMSUNG-([A-Za-z0-9\\-]+)",device_replacement:"Samsung $1",manufacturer:"Samsung"},{regex:"SAMSUNG\\; ([A-Za-z0-9\\-]+)",device_replacement:"Samsung $1",manufacturer:"Samsung"},{regex:"Softbank/1\\.0/([A-Za-z0-9]+)",device_replacement:"Softbank $1",other:!0},{regex:"Softbank/2\\.0/([A-Za-z0-9]+)",device_replacement:"Softbank $1",other:!0},{regex:"(hiptop|avantgo|plucker|xiino|blazer|elaine|up.browser|up.link|mmp|smartphone|midp|wap|vodafone|o2|pocket|mobile|pda)",device_replacement:"Generic Smartphone"},{regex:"^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\\-|airn|alav|asus|attw|au\\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\\-n|bw\\-u|beck|benq|bilb|blac|c55/|cdm\\-|chtm|capi|comp|cond|craw|dall|dbte|dc\\-s|dica|ds\\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\\-|fly\\_|g\\-mo|g1 u|g560|gf\\-5|grun|gene|go.w|good|grad|hcit|hd\\-m|hd\\-p|hd\\-t|hei\\-|hp i|hpip|hs\\-c|htc |htc\\-|htca|htcg)",device_replacement:"Generic Feature Phone"},{regex:"^(htcp|htcs|htct|htc\\_|haie|hita|huaw|hutc|i\\-20|i\\-go|i\\-ma|i230|iac|iac\\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\\-|klon|lexi|lg g|lg\\-a|lg\\-b|lg\\-c|lg\\-d|lg\\-f|lg\\-g|lg\\-k|lg\\-l|lg\\-m|lg\\-o|lg\\-p|lg\\-s|lg\\-t|lg\\-u|lg\\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\\-|lge/|lynx|leno|m1\\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\\-|nem\\-|newg|neon)",device_replacement:"Generic Feature Phone"},{regex:"^(netf|noki|nzph|o2 x|o2\\-x|opwv|owg1|opti|oran|ot\\-s|p800|pand|pg\\-1|pg\\-2|pg\\-3|pg\\-6|pg\\-8|pg\\-c|pg13|phil|pn\\-2|pt\\-g|palm|pana|pire|pock|pose|psio|qa\\-a|qc\\-2|qc\\-3|qc\\-5|qc\\-7|qc07|qc12|qc21|qc32|qc60|qci\\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\\-|scp\\-|sdk/|se47|sec\\-|sec0|sec1|semc|sgh\\-|shar|sie\\-|sk\\-0|sl45|slid|smb3|smt5|sp01|sph\\-|spv |spv\\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\\-mo|t218|t250|t600|t610|t618|tcl\\-|tdg\\-|telm|tim\\-|ts70|tsm\\-|tsm3|tsm5|tx\\-9|tagt)",device_replacement:"Generic Feature Phone"},{regex:"^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\\-|your|zte\\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\\-|webc|whit|wmlb|xda\\-|xda\\_)",device_replacement:"Generic Feature Phone"},{regex:"(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\\-webcrawler|converacrawler|dataparksearch|findlinks)",device_replacement:"Spider"}],mobile_browser_families:["Firefox Mobile","Opera Mobile","Opera Mini","Mobile Safari","webOS","IE Mobile","Playstation Portable","Nokia","Blackberry","Palm","Silk","Android","Maemo","Obigo","Netfront","AvantGo","Teleca","SEMC-Browser","Bolt","Iris","UP.Browser","Symphony","Minimo","Bunjaloo","Jasmine","Dolfin","Polaris","BREW","Chrome Mobile","Chrome Mobile iOS","UC Browser","Tizen Browser"]};a.parsers=["device_parsers","browser_parsers","os_parsers","mobile_os_families","mobile_browser_families"],a.types=["browser","os","device"],a.regexes=b||function(){var b={};return a.parsers.map(function(a){b[a]=[]}),b}(),a.families=function(){var b={};return a.types.map(function(a){b[a]=[]}),b}();var c=Array.prototype,d=(Object.prototype,Function.prototype,c.forEach);c.indexOf;var e=function(a,b){for(var c={},d=0;b.length>d&&!(c=b[d](a));d++);return c},f=function(a,b){g(a,function(a){g(b,function(b){delete a[b]})})},g=forEach=function(a,b,c){if(null!=a)if(d&&a.forEach===d)a.forEach(b,c);else if(a.length===+a.length)for(var e=0,f=a.length;f>e;e++)b.call(c,a[e],e,a);else for(var g in a)_.has(a,g)&&b.call(c,a[g],g,a)},h=function(a){return!(!a||void 0===a||null==a)},i=function(a){var b="";return a=a||{},h(a)&&h(a.major)&&(b+=a.major,h(a.minor)&&(b+="."+a.minor,h(a.patch)&&(b+="."+a.patch))),b},j=function(a){a=a||{};var b=i(a);return b&&(b=" "+b),a&&h(a.family)?a.family+b:""};return a.parse=function(b){var c=function(b){return a.regexes[b+"_parsers"].map(function(a){function c(b){var c=b.match(d);if(!c)return null;var g={};return g.family=(e?e.replace("$1",c[1]):c[1])||"other",g.major=parseInt(f?f:c[2])||null,g.minor=c[3]?parseInt(c[3]):null,g.patch=c[4]?parseInt(c[4]):null,g.tablet=a.tablet,g.man=a.manufacturer||null,g}var d=RegExp(a.regex),e=a[("browser"===b?"family":b)+"_replacement"],f=a.major_version_replacement;return c})},d=function(){},g=c("browser"),k=c("os"),l=c("device"),m=new d;m.source=b,m.browser=e(b,g),h(m.browser)?(m.browser.name=j(m.browser),m.browser.version=i(m.browser)):m.browser={},m.os=e(b,k),h(m.os)?(m.os.name=j(m.os),m.os.version=i(m.os)):m.os={},m.device=e(b,l),h(m.device)?(m.device.name=j(m.device),m.device.version=i(m.device)):m.device={tablet:!1,family:"Other"};var n={};return a.regexes.mobile_browser_families.map(function(a){n[a]=!0}),a.regexes.mobile_os_families.map(function(a){n[a]=!0}),m.device.type="Spider"===m.browser.family?"Spider":m.browser.tablet||m.os.tablet||m.device.tablet?"Tablet":n.hasOwnProperty(m.browser.family)?"Mobile":"Desktop",m.device.manufacturer=m.browser.man||m.os.man||m.device.man||null,f([m.browser,m.os,m.device],["tablet","man"]),m},a}();"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=b),exports.detect=b):a.detect=b,"function"==typeof define&&define.amd&&define(function(){return b})}(window),function(){"use strict";var a=function(a,b,c){a.hasOwnProperty(b)?console.warn("Property already exist"):a[b]=c};amp.viewerSettings={viewerConfigs:{v:"1.1.3",target:"#amp-container",client:"playground",imageBasePath:"//i1.adis.ws/",errImg:"404",errCallback:function(){},cacheControl:1,cacheWindow:315569259747,fullNavHeight:100,templates:{thumb:"w=85&h=85&qlt=default",desktop:{main:"w=1000&h=1000",mainRetina:"w=2000&h=2000"},desktopFull:{main:"w=1000",mainRetina:"w=2000"},mobile:{main:"w=500&h=500",mainRetina:"w=1000&h=1000"}},tooltips:{offsets:{left:-102,top:-39},displayTime:3e3,desktop:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}},desktopFull:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}},mobile:{image:{noTouch:{text:"Click to zoom"},touch:{text:"Tap to zoom"},doubleTouch:{text:"Double tap to zoom"}},spin:{noTouch:{text:"Drag to rotate"},touch:{text:"Tap to rotate"},doubleTouch:{text:"Double tap to rotate"}},video:{play:{noTouch:{text:""},touch:{text:""}},pause:{noTouch:{text:""},touch:{text:""}}}}},navIconsMain:{next:"icon icon-right bla-main-next",prev:"icon icon-left bla-main-prev"},navIconsNav:{next:"icon icon-right bla-nav-next",prev:"icon icon-left bla-nav-prev"},navIconsPortraitNav:{next:"icon icon-right bla-portrait-next",prev:"icon icon-left bla-portrait-prev"},zoomInlineDoubleTap:!0,doubleTapTime:250,ampConfigs:{navElementsWidthPx:100,navElementsWidthPxMobile:50,navElementsCount:{forDesktop:5,forDesktopFull:4},mainContainerCarousel:{width:1,height:1,responsive:!0,start:1,loop:!1,dir:"horz",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"horz",distance:100},animDuration:200,layout:"standard",onActivate:{select:!0,goTo:!0},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0},mainContainerNav:{on:"goTo",action:"select",selector:".nav-container .list"},mainContainerSpin:{width:1,height:1,responsive:!0,delay:100,autoplay:!1,gesture:{enabled:!0,fingers:1},loop:!0,start:1,momentum:!0,minDistance:50,friction:.97,dragDistance:200,preload:"created",preloadType:"full",activate:"down",dir:"normal",cursor:{active:"pointer",inactive:"pointer"},play:{onLoad:!0,onVisible:!0,repeat:1,delay:600},lazyLoad:!1,orientation:"horz"},mainContainerSpin3d:{loop:!1,dragDistance:200,orientation:"vert",preload:"created",preloadType:"window",width:1,height:1,gesture:{enabled:!0,fingers:1}},mainContainerVideo:{width:1,height:1,center:!0,responsive:!0,autoplay:!1,loop:!1,muted:!1,controls:!0,pauseOnHide:!0,nativeControlsForTouch:!1,plugins:{videoJsResolutionSwitcher:{default:"Medium"}}},mainContainerZoomInline:{transforms:[],scaleMax:3,scaleStep:.5,scaleSteps:!0,pinch:!0,pan:!0,events:{zoomIn:"",zoomOut:"",move:""},activation:{inGesture:!0},preload:!1,preventVisibleZoomOut:!0},navContainerCarousel:{height:1,responsive:!0,start:1,loop:!1,dir:"horz",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"horz",distance:50},animDuration:200,layout:"standard",onActivate:{select:!0,goTo:!1},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0},navContainerNav:{on:"select",action:"select",selector:".main-container .list"},image:{preload:"created",insertAfter:!1,errImg:null}}},portraitConfigs:function(){var b=this;a(b.viewerConfigs.ampConfigs,"navContainerCarouselPortrait",{height:"100%",responsive:!0,start:1,loop:!1,dir:"vert",autoplay:!1,gesture:{enabled:!0,fingers:1,dir:"vert",distance:50},animDuration:500,layout:"standard",onActivate:{select:!0,goTo:!1},animate:!0,easing:"linear",preferForward:!0,preloadNext:!0}),a(b.viewerConfigs.ampConfigs,"mainContainerSpinPortrait",{height:"100%",responsive:!0,delay:100,autoplay:!1,gesture:{enabled:!0,fingers:1},loop:!0,start:1,momentum:!0,minDistance:50,friction:.97,dragDistance:200,preload:"created",preloadType:"full",activate:"down",dir:"normal",cursor:{active:"pointer",inactive:"pointer"},play:{onLoad:!0,onVisible:!0,repeat:1},lazyLoad:!1,orientation:"horz"}),a(b.viewerConfigs.ampConfigs,"mainContainerVideoPortrait",{height:"100%",responsive:!0,autoplay:!1,loop:!1,muted:!1,controls:!0,pauseOnHide:!0,nativeControlsForTouch:!0,plugins:{videoJsResolutionSwitcher:!0}})},overwritePortraitSettings:function(a){a.ampConfigs.mainContainerCarousel.width=.8,a.ampConfigs.mainContainerCarousel.height=1.2,a.templates={thumb:"w=85&h=85&qlt=default",thumbPortrait:"w=67&h=89&qlt=default",desktop:{main:"w=1010&h=1416",mainRetina:"w=2020&h=2832"},desktopFull:{main:"w=1010&h=1416",mainRetina:"w=2020&h=2832"},mobile:{main:"w=505&h=708",mainRetina:"w=1010&h=1416"}}}}}(),function(a,b){"use strict";var c="Amplience Viewer",d=function(c){var d=this,e=amp.viewerSettings.viewerConfigs;"portrait"===c.view?(amp.viewerSettings.overwritePortraitSettings(e),amp.viewerSettings.portraitConfigs(),d.isPortraitView=!0):"landscape"===c.view?d.isLandscapeView=!0:d.isSquareView=!0,d.settings=b.extend(!0,{},e,c),d.listVisible=d.settings.ampConfigs.mainContainerCarousel.listVisible,("number"!=typeof d.listVisible||d.listVisible<1)&&(d.listVisible=1),d.settings.locale&&d.settings.locale.length>0&&d.settings.ampConfigs.mainContainerZoomInline.transforms.push("locale="+d.settings.locale),d.views={desktopNormalView:"desktopNormalView",desktopFullView:"desktopFullView",mobileNormalView:"mobileNormalView"},d.assets=[],d.currentAssetIndex=0,d.canTouch=!!("ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),d.wrapper=b('
    '),d.deviceWidth=a.innerWidth,d.controller(),d.tags=[],d.IE=d.isIE(),d.tooltipsTimeout=[]};d.prototype.controller=function(){var a=this;amp.init({client_id:a.settings.client,di_basepath:a.settings.imageBasePath,cache_window:a.settings.cacheWindow}),window.ecommBridge&&a.settings.ecommBridge&&this.bridgeConnector.initAll(),a.applyImgTemplates(),b(a.settings.target).append(a.wrapper);var d=a.initSetData();a.getSet(d).then(function(b){a.assets=b,a.renderInitialView()}).catch(function(a){console.warn(a,c+" unable to get set list.")})},d.prototype.initSetData=function(){var a=this,b=a.bridgeConnector.page;return null!==b&&a.settings.ecommBridge?b.mediaList&&b.mediaList.constructor===Array&&b.mediaList.length>0?a.returnSetData(b.mediaList):b.mediaSet&&"string"==typeof b.mediaSet&&b.mediaSet.length>0?a.returnSetData(b.mediaSet):void 0:a.returnSetData(a.settings.set)},d.prototype.returnSetData=function(a){var b=this,c="&v="+b.settings.cacheControl;return a.constructor===Array?(b.bridgeConnector.enrichMediaListWithParams(a,{transform:c}),a):{name:a,type:"s",transform:c}},d.prototype.secureData=function(a){if(this.settings.secure){var b=JSON.stringify(a);b=b.replace(/http:\/\//g,"https://"),a=JSON.parse(b)}return a},d.prototype.getSet=function(a){var b=this;return new Promise(function(c,d){amp.get(a,function(d){var e=null;e=a.constructor===Array?b.bridgeConnector.convertListToSet(a,d).items:d[a.name].items,c(e)},function(){b.getImage(b.settings.errImg).then(function(a){b.settings.errCallback.call(b),c([{src:a.url}])})},!1,!1,b.secureData.bind(b))})},d.prototype.getImage=function(a){var b=this;return new Promise(function(c,d){amp.get({name:a,type:"i",transform:"&v="+b.settings.cacheControl},function(b){c(b[a])},function(){c({url:"//i1.adis.ws/i/playground/404"})},!1,!1,b.secureData.bind(b))})},d.prototype.changeSet=function(a){var b=this;null!==b.bridgeConnector.page&&b.settings.ecommBridge?a.constructor===Array&&a.length>0?b.bridgeConnector.page.mediaList=a:"string"==typeof a&&a.length>0&&(b.bridgeConnector.page.mediaset=a,b.bridgeConnector.page.mediaList=null):b.settings.set=a;var d=b.returnSetData(a);b.getSet(d).then(function(a){b.assets=a,b.currentAssetIndex=0,b.renderInitialView()}).catch(function(a){console.warn(a,c+" unable to get set list.")})},d.prototype.isIE=function(){return !!/MSIE [0-9]{1,}/.test(navigator.userAgent)||!(!/Trident\/\d./i.test(navigator.userAgent)&&!/Edge\/\d./i.test(navigator.userAgent));},d.prototype.isMobile=function(){return!!this.settings.isMobile||a.innerWidth<=768},d.prototype.renderInitialView=function(){var a=this;a.currentView=a.isMobile()?a.views.mobileNormalView:a.views.desktopNormalView,a.renderView(a.currentView)},d.prototype.renderView=function(a,d){var e=this,d=d||!1;switch(e.destroyAmpWidgets(),a){case e.views.desktopNormalView:e.renderDesktopNormalView();break;case e.views.desktopFullView:e.renderDesktopFullView();break;case e.views.mobileNormalView:e.renderMobileNormalView();break;default:console.warn(c+": Unknown view: "+a+". Viewer desktopNormalView."),e.renderDesktopNormalView()}switch(a===e.views.desktopFullView?(this._scrollPosition=b(window).scrollTop(),b("html, body").addClass("amp-no-scroll")):(b("html, body").removeClass("amp-no-scroll"),b(window).scrollTop(this._scrollPosition)),e.mainContainerList=e.wrapper.find(".main-container .list"),e.slides=!1,e.navContainerList=e.wrapper.find(".nav-container .list"),e.tooltips=e.wrapper.find(".main-container .tooltip"),e.tooltipsText=e.tooltips.find("span.text"),e.bindGenericEvents(),e.bindAmpEvents(),e.bindNavigationEvents(),e.bindSpinEvents(),e.initImagesSrcset(),e.initAmpWidgets(d),e.applyNavigationStyles(),e.checkMainContainerNavArrows(),e.checkNavContainerNavArrows(),e.checkZoomIcons(),e.checkMainContainerSlidesVisibility(),a){case e.views.desktopNormalView:e.bindDesktopNormalViewEvents();break;case e.views.desktopFullView:e.bindDesktopFullViewEvents();break;case e.views.mobileNormalView:e.bindMobileNormalViewEvents()}e.settings.initCallback&&e.settings.initCallback.apply(e)},d.prototype.getTemplateData=function(a){var c=this,d={items:c.assets,templates:c.getTemplates(),locale:{first:"",second:""},view:""};if(c.settings.locale&&b.trim(c.settings.locale).length>0){var e="locale="+c.settings.locale;d.locale.first="?"+e,d.locale.second="&"+e}return c.settings.view&&c.settings.view.length>0&&(d.view=c.settings.view),d},d.prototype.renderDesktopNormalView=function(){var a=this;a.currentView=a.views.desktopNormalView,a.wrapper.html(amp.templates.desktopNormalView(a.getTemplateData())),a.cloneTooltip(a.listVisible)},d.prototype.cloneTooltip=function(a){for(var b=this.wrapper.find(".main-container .tooltip"),c=1;c0)i.ampSpin(d.mainContainerSpin3d),j.each(function(a){var c=b.extend(!0,{},d.mainContainerSpin,{play:{onVisible:!1,onLoad:!1},preloadType:"window"});b(this).ampSpin(c)});else{var k=d.mainContainerSpin;1==k.play.onVisible&&(c.spinVisible=!0,k.play.onVisible=!1),i.ampSpin(k)}}else if(h.hasOwnProperty("media")){var l=d.mainContainerVideo;c.settings.view&&c.isPortraitView&&c.currentView===c.views.desktopNormalView&&(l=d.mainContainerVideoPortrait,l.nativeControlsForTouch=!1);var m=c.mainContainerList.find("#"+h.name).ampVideo(l);m.find("video").on("touchstart",function(){2==m.ampVideo("state")?m.ampVideo("play"):m.ampVideo("pause")}), c.tags.push({alias:"videoContainer",$tag:m})}else c.currentView!==c.views.desktopNormalView&&c.mainContainerList.find("> > li:eq("+g+") img").ampZoomInline(d.mainContainerZoomInline)}},d.prototype.destroyAmpWidgets=function(){var a=this;a.tags.length=0;for(var c=0;c0&&e.ampVideo("destroy")}}},d.prototype.navMove=function(a){var c=this,d=b(a),e=d.next();e.length>0&&(e.hasClass("amp-visible")?d.prev().hasClass("amp-visible")||c.navContainerList.ampCarousel("prev"):c.navContainerList.ampCarousel("next"))},d.prototype.navigateToActiveThumb=function(){var a=this,b=a.navContainerList.find(".amp-slide"),c=b.filter(".amp-selected"),d=Math.floor(a.navContainerList.width()/a.settings.ampConfigs.navElementsWidthPxMobile),e=b.nextAll().length*a.settings.ampConfigs.navElementsWidthPxMobile;b.prevAll().length,a.settings.ampConfigs.navElementsWidthPxMobile;0===c.index()||c.index()===b.length-1?a.navContainerList.ampCarousel("goTo",c.index()+1):e>=d?a.navContainerList.ampCarousel("goTo",c.index()):a.navContainerList.ampCarousel("goTo",c.index()+2)},d.prototype.bindNavigationEvents=function(){var a=this;a.bindIconClickEvent(a.wrapper.find(".main-container-prev"),function(){a.mainContainerMove("prev")}),a.bindIconClickEvent(a.wrapper.find(".main-container-next"),function(){a.mainContainerMove("next")}),a.bindIconClickEvent(a.wrapper.find(".nav-container-prev"),function(){a.navContainerMove("prev")}),a.bindIconClickEvent(a.wrapper.find(".nav-container-next"),function(){a.navContainerMove("next")})},d.prototype.navContainerMove=function(a){var b=this,c=b.getNavigationVisibleSlidesInfo(),d=c.firstVisible+1;"prev"===a?d=c.isFirst?1:c.firstVisible:"next"===a&&(d=c.isLast?c.firstVisible+1:c.firstVisible+2),b.navContainerList.ampCarousel("goTo",d)},d.prototype.mainContainerMove=function(a){var b=this,c=b.getMainVisibleSlidesInfo(),d=b.mainContainerList.find(".amp-slide"),e=c.firstVisible+1;"prev"===a?e=c.isFirst?1:c.firstVisible:"next"===a&&(e=c.isLast?c.firstVisible+1:c.firstVisible+2),b.mainContainerList.ampCarousel("goTo",e),d.removeClass("amp-visible"),d.eq(e-1).addClass("amp-visible")},d.prototype.initTooltips=function(){var a=this;a.slides||(a.slides=a.mainContainerList.find("li.amp-slide")),a.slides.off("mousemove mouseout"),a.tooltips.attr({style:""}),a.tooltips.css({display:"none"});for(var b=a.currentAssetIndex,c=0;c0)return;var d=a.assets[b+c];if(!d)return;if(d.hasOwnProperty("set")){var e=!1;d.set.items&&d.set.items.length>0&&d.set.items[0].set&&(e=!0),a.initSpinTooltip(e,c)}else d.hasOwnProperty("media")?a.initVideoTooltip(c):a.initImageTooltip(c)}},d.prototype.initImageTooltip=function(a){var c=this,d="",e=c.currentAssetIndex+a,f=b(c.tooltips[a]),g=b(c.tooltipsText[a]);switch(f.attr({class:"tooltip image"}),c.currentView){case c.views.desktopNormalView:if(c.canTouch)d=c.settings.zoomInlineDoubleTap?c.settings.tooltips.desktop.image.doubleTouch.text:c.settings.tooltips.desktop.image.touch.text,f.css({position:"absolute"}),g.text(d),c.fadeOutTooltip(a);else{f.fadeOut(0);c.mainContainerList.css("margin-left").replace("px","");g.text(c.settings.tooltips.desktop.image.noTouch.text),b(c.slides[e]).on("mousemove",function(a){f.css({top:a.clientY-c.settings.tooltips.offsets.top,left:a.clientX-c.settings.tooltips.offsets.left,display:"block"})}),b(c.slides[e]).on("mouseout",function(){f.fadeOut(0)})}break;case c.views.desktopFullView:d=c.settings.zoomInlineDoubleTap?c.settings.tooltips.desktopFull.image.doubleTouch.text:c.settings.tooltips.desktopFull.image.touch.text,g.text(c.canTouch?d:c.settings.tooltips.desktopFull.image.noTouch.text),f.fadeOut(0);break;case c.views.mobileNormalView:d=c.settings.zoomInlineDoubleTap?c.settings.tooltips.mobile.image.doubleTouch.text:c.settings.tooltips.mobile.image.touch.text,g.text(c.canTouch?d:c.settings.tooltips.mobile.image.noTouch.text),c.fadeOutTooltip(a)}},d.prototype.initSpinTooltip=function(a,c){var d=this,e="",f=b(d.tooltips[c]),g=b(d.tooltipsText[c]),h=a?"spin-3d":"spin";switch(f.attr({class:"tooltip "+h}),f.css({display:"block"}),d.currentView){case d.views.desktopNormalView:if(e=d.settings.zoomInlineDoubleTap?d.settings.tooltips.desktop.spin.doubleTouch.text:d.settings.tooltips.desktop.spin.touch.text,g.text(d.canTouch?e:d.settings.tooltips.desktop.spin.noTouch.text),d.listVisible>1){var i=parseInt(f.css("margin-left")),j=f.outerWidth(),k=b(d.slides[c]).outerWidth(),l=(k-j)/2-i+k*c;f.css({left:l+"px"}),j>k&&f.css({transform:"scale(0.5)"})}break;case d.views.desktopFullView:e=d.settings.zoomInlineDoubleTap?d.settings.tooltips.desktopFull.spin.doubleTouch.text:d.settings.tooltips.desktopFull.spin.touch.text,g.text(d.canTouch?e:d.settings.tooltips.desktopFull.spin.noTouch.text);break;case d.views.mobileNormalView:e=d.settings.zoomInlineDoubleTap?d.settings.tooltips.mobile.spin.doubleTouch.text:d.settings.tooltips.mobile.spin.touch.text,g.text(d.canTouch?e:d.settings.tooltips.mobile.spin.noTouch.text)}d.fadeOutTooltip(c)},d.prototype.initVideoTooltip=function(a){var c=this,d=b(c.tooltips[a]);b(c.tooltipsText[a]);d.attr({class:"tooltip video"})},d.prototype.fadeOutTooltip=function(a){var c=this;c.tooltipsTimeout[a]&&(clearTimeout(c.tooltipsTimeout[a]),c.tooltipsTimeout[a]=!1),b(c.tooltips[a]).stop(),c.tooltipsTimeout[a]=setTimeout(function(){b(c.tooltips[a]).fadeOut()},c.settings.tooltips.displayTime)},d.prototype.doubleTapEvent=function(a){var c=this,d=0,e=0,f=!0,g={x:0,y:0},h={x:1e3,y:1e3},i={x:0,y:0},j={x:1e3,y:1e3};return a.on("touchstart",function(a){if(c.isZoomCycle)return d=0,e=0,a.preventDefault(),void a.stopPropagation();var b=new Date;g={x:Math.abs(a.originalEvent.touches[0].pageX)||0,y:Math.abs(a.originalEvent.touches[0].pageY)||0},f?(i=g,f=!1):(j=g,f=!0),e=b}),a.on("touchend",function(a){a.preventDefault();var e=new Date,f=e-d;h={x:Math.abs(a.originalEvent.changedTouches[0].pageX)||1e3,y:Math.abs(a.originalEvent.changedTouches[0].pageY)||1e3};var k={x:Math.abs(j.x-i.x),y:Math.abs(j.y-i.y)},l={x:Math.abs(h.x-g.x),y:Math.abs(h.y-g.y)};k.x<50&&k.y<50&&l.x<50&&l.y<50&&(f0?(b(this).trigger("doubletap"),b(this).trigger("doubletapend")):b(a.target).hasClass("amp-slide")&&a.stopPropagation()),d=e}),"doubletap"},d.prototype.bindDesktopNormalViewEvents=function(){var a=this,b=a.mainContainerList.find(".zoom-trap"),c=a.canTouch&&a.settings.zoomInlineDoubleTap?a.doubleTapEvent(b):"click";b.on(c,function(){a.renderView(a.views.desktopFullView)})},d.prototype.bindDesktopFullViewEvents=function(){var a=this;a.bindIconClickEvent(a.wrapper.find(".main-container .close"),function(){a.renderView(a.views.desktopNormalView,!0)}),a.bindIconClickEvent(a.wrapper.find(".panel .plus"),function(){a.zoomIn()}),a.bindIconClickEvent(a.wrapper.find(".panel .minus"),function(){a.zoomOut()}),a.bindZoomEvents(a.zoomCycle)},d.prototype.bindMobileNormalViewEvents=function(){var a=this;a.bindIconClickEvent(a.wrapper.find(".main-container .close"),function(){a.zoomOutFull()}),a.bindZoomEvents(a.zoomCycle)},d.prototype.bindSpinEvents=function(){var a=this,c=a.mainContainerList.find(".spin-trap"),d=a.mainContainerList.find(".spin-trap + ul");a.canTouch?(a.bindTapEvent(c,function(){var c=b(this);c.addClass("active-for-scrolling"),c.next().hasClass("amp-outer-spin")&&c.parent().on("touchstart",a._prevent)}),a.bindTapEvent(d,function(){var c=b(this),d=b(this).parent();d.find(".spin-trap").removeClass("active-for-scrolling"),c.hasClass("amp-outer-spin")&&d.off("touchstart",a._prevent)})):c.css({display:"none"})},d.prototype.bindZoomEvents=function(a){var b=this,c=b.mainContainerList.find(".zoom-trap");b.bindTapEvent(c,a.bind(b))},d.prototype._resize=function(){this.checkView(),(this.currentView===this.views.mobileNormalView||this.isPortraitView&&this.currentView===this.views.desktopNormalView)&&(this.navigateToActiveThumb(),this.applyNavigationStyles(),this.checkNavContainerNavArrows())},d.prototype._orientationChange=function(){var a=this;setTimeout(function(){a._resize()},300)},d.prototype.bindGenericEvents=function(){var a=this;b(window).off("resize",this._resize),b(window).on("resize",this._resize.bind(this)),b(document).off("gesturestart",a._prevent),b(document).on("gesturestart",a._prevent.bind(this)),window.removeEventListener("orientationchange",a._orientationChange),window.addEventListener("orientationchange",a._orientationChange.bind(this));var c=[],d=!1,e=!1;b(document).off("touchmove.viewerkit"),b(document).on("touchmove.viewerkit",function(f){if(f.originalEvent.touches[0]&&void 0!==f.originalEvent.touches[0].clientX&&(d||(d=b(f.target).parents(".amp-carousel")),d&&d.length>0)){var g={clientX:f.originalEvent.touches[0].clientX,clientY:f.originalEvent.touches[0].clientY};c.push(g);var h=Math.abs(c[c.length-1].clientX-c[0].clientX),i=Math.abs(c[c.length-1].clientY-c[0].clientY);!e&&h>i&&(d.on("touchmove",a._prevent),e=!0),e&&h<=i&&(d.off("touchmove",a._prevent),e=!1)}}),b(document).off("touchend.viewerkit"),b(document).on("touchend.viewerkit",function(b){c=[],e&&d&&d.length>0&&(d.off("touchmove",a._prevent),e=!1),d=!1})},d.prototype.startSpin=function(a){var b=this,c=b.assets[a];if(c&&"set"===c.type&&"set"!=c.set.items[0].type){var d=b.mainContainerList.find(".amp-slide").eq(a).find(".amp-spin"),e=void 0!==d.data()&&(d.data()["amp-ampSpin"]||d.data().ampAmpSpin);d.length>0&&(!e||1==e._loaded)&&setTimeout(function(){d.ampSpin("playRepeat",1)},b.settings.ampConfigs.mainContainerCarousel.animDuration)}},d.prototype.bindAmpEvents=function(){var a=this;a.mainContainerList.on("ampcarouselcreated ampcarouselchange",function(c,d){b(".amp-spin").find(".amp-frame").css({"margin-left":"-1px"}),a.prevAssetIndex=a.currentAssetIndex,a.currentAssetIndex=d.index-1,a.zoomOutFull(),a.initTooltips(),a.checkSpins(),a.checkMainContainerNavArrows(),a.checkZoomIcons(),a.checkMainContainerSlidesVisibility(a.settings.ampConfigs.mainContainerCarousel.animDuration),a.spinVisible&&a.startSpin(a.currentAssetIndex)}),a.navContainerList.on("ampcarouselcreated ampcarouselchange",function(b,c){a.checkNavContainerNavArrows(),a.currentView===a.views.mobileNormalView&&"ampcarouselcreated"===b.type&&a.navContainerList.find(".amp-slide").on("mouseup",function(){a.navMove(this)})}),a.mainContainerList.find(".zoom-trap > img").on("ampzoominlinezoomedin ampzoominlinezoomedinfull ampzoominlinezoomedout ampzoominlinezoomedoutfull",function(c,d){a.checkZoomIcons(),a.toggleZoomScrolling(b(this).parent().find(".amp-zoomed"))}).on("ampzoominlinezoomedin ampzoominlinezoomedinfull",function(b,c){a.lastZoomDir="In"}).on("ampzoominlinezoomedout ampzoominlinezoomedoutfull",function(b,c){a.lastZoomDir="Out"}),a.mainContainerList.find(".video").on("ampvideofullscreenchange",function(a,c){2!==b(a.target).ampVideo("state")&&c.player&&c.player.isFullscreen_&&setTimeout(function(){b(a.target).ampVideo("play")},1e3)})},d.prototype.checkMainContainerNavArrows=function(){var a=this,b=a.currentAssetIndex;a.wrapper.find(".main-container .amp-js-nav").removeClass("disabled"),0===b&&a.wrapper.find(".main-container-prev").addClass("disabled"),a.currentView===a.views.desktopNormalView&&a.listVisible>1?b>=a.assets.length-a.listVisible&&a.wrapper.find(".main-container-next").addClass("disabled"):b===a.assets.length-1&&a.wrapper.find(".main-container-next").addClass("disabled")},d.prototype.checkNavContainerNavArrows=function(){var a=this;a.wrapper.find(".nav-container > .amp-js-nav").removeClass("disabled");var b=a.getNavigationVisibleSlidesInfo();b.isFirst&&a.wrapper.find(".nav-container-prev").addClass("disabled"),b.isLast&&a.wrapper.find(".nav-container-next").addClass("disabled")},d.prototype.checkView=function(){var a=this;a.isMobile()&&a.currentView!==a.views.mobileNormalView?a.renderView(a.views.mobileNormalView):a.isMobile()||a.currentView!==a.views.mobileNormalView||a.renderView(a.views.desktopNormalView)},d.prototype.getAmpConfigs=function(){var a=this,b=a.settings.ampConfigs;switch(a.currentView){case a.views.desktopNormalView:a.listVisible>1&&a.mainContainerList.css({width:100/a.listVisible+"%",overflow:"visible",margin:0}),a.settings.view||a.isPortraitView||(b.navContainerCarousel.width=a.settings.ampConfigs.navElementsCount.forDesktop,b.navContainerCarousel.gesture.enabled=!0);break;case a.views.desktopFullView:a.listVisible>1&&a.mainContainerList.css("width","100%"),b.navContainerCarousel.width=a.settings.ampConfigs.navElementsCount.forDesktopFull;break;case a.views.mobileNormalView:a.listVisible>1&&a.mainContainerList.css("width","100%");var c=a.wrapper.width(),d=a.assets.length,e=d*b.navElementsWidthPxMobile,f=2*parseFloat(a.wrapper.find(".nav-container").css("padding-left"),10);e>c?(b.navContainerCarousel.width=Math.floor((c-f)/b.navElementsWidthPxMobile),b.navContainerCarousel.gesture.enabled=!0):(b.navContainerCarousel.width=a.assets.length,b.navContainerCarousel.gesture.enabled=!1)}return b.mainContainerCarousel.start=a.currentAssetIndex+1,b.navContainerCarousel.start=a.currentAssetIndex+1,b},d.prototype.applyNavigationStyles=function(){var a=this,b=a.getAmpConfigs(),c=a.wrapper.find(".nav-container"),d=c.find("> .amp-js-nav");if(a.settings.view&&a.isPortraitView&&a.currentView===a.views.desktopNormalView){return c.find(".amp-slide.amp-visible").length===a.assets.length?(d.css({display:"none"}),c.addClass("amp-without-thumbs")):(d.css({display:"block"}),c.removeClass("amp-without-thumbs"),a.checkNavContainerNavArrowsStyle()),!1}a.assets.length<=b.navContainerCarousel.width?d.css({display:"none"}):d.css({display:"block"});var e=d.width(),f=100/b.navContainerCarousel.width,g=b.navContainerCarousel.width*b.navElementsWidthPx+4*e;a.currentView===a.views.mobileNormalView&&(a.assets.length<=b.navContainerCarousel.width?c.css("padding",0):(a.checkNavContainerNavArrowsStyle(),c.css("padding","")));var h=b.navContainerCarousel.width*b.navElementsWidthPxMobile+2*parseFloat(c.css("padding-left"),10);c.css({"max-width":a.currentView===a.views.mobileNormalView?h:g});var i=a.currentView!==a.views.mobileNormalView?"calc("+f+"% - 20px)":b.navElementsWidthPxMobile+"px";a.navContainerList.find(".amp-slide").css("width",i)},d.prototype.getNavigationVisibleSlidesInfo=function(){for(var a=this,b=a.navContainerList.find(".amp-slide"),c=b.length,d=0;d=b.length-f}},d.prototype.getMainVisibleSlidesInfo=function(){for(var a=this,b=a.mainContainerList.find(".amp-slide"),c=b.length,d=0;d=b.length-f}},d.prototype.zoomIn=function(){var a=this,b=a.getZoomSlide();b.length>0&&b.ampZoomInline("zoomIn")},d.prototype.zoomOut=function(){var a=this,b=a.getZoomSlide();b.length>0&&b.ampZoomInline("zoomOut")},d.prototype.zoomInFull=function(){var a=this,b=a.getZoomSlide();b.length>0&&b.ampZoomInline("zoomInFull")},d.prototype.zoomOutFull=function(){var a=this;if(!a.isZoomCycle){var c=a.getZoomSlide();b.each(a._preventElements,function(b,c){c.off("touchmove",a._prevent)}),a._preventElements=[],a.isZoomed()&&(a.isZoomCycle=!0,c.ampZoomInline("zoomOutFull"));var d=a.getZoomSlide(a.prevAssetIndex);d.length>0&&d.ampZoomInline("zoomOutFull"),setTimeout(function(){a.isZoomCycle=!1},600)}},d.prototype.zoomToggle=function(){var a=this,b=a.getZoomSlide();if(b.length>0){var c=b.ampZoomInline("state"),d=1+c.scaleMax-c.scale;b.ampZoomInline("setScale",d)}},d.prototype.zoomCycle=function(){var a=this;if(!a.isZoomCycle){var b=a.getZoomSlide();if(b.length>0){a.isZoomCycle=!0;var c=a.getNextCycleDir();b.ampZoomInline("zoom"+c)}setTimeout(function(){a.isZoomCycle=!1},500)}},d.prototype.getNextCycleDir=function(){var a=this,b=a.getZoomSlide(),c=b.ampZoomInline("state");return 1===c.scale?"In":c.scale===c.scaleMax?"Out":a.lastZoomDir},d.prototype.getZoomSlide=function(a){var b=this,a=void 0!==a?a:b.currentAssetIndex;return b.mainContainerList.find("> > li:eq("+a+") .amp-zoom")},d.prototype.toggleZoomScrolling=function(a){var c=this,d=this.getZoomSlide(),e=d.ampZoomInline("state");b.each(c._preventElements,function(a,b){b.off("touchmove",c._prevent)}),c._preventElements=[],c._preventElements.push(a),1===e.scale?a.off("touchmove",c._prevent):a.on("touchmove",c._prevent)},d.prototype.checkZoomIcons=function(){var a=this,c=a.getZoomSlide(),d=c.ampZoomInline("state");switch(a.currentView){case a.views.desktopFullView:var e=a.wrapper.find(".panel .plus"),f=a.wrapper.find(".panel .minus");e.add(f).removeClass("disabled"),c.length>0?(1===d.scale&&f.addClass("disabled"),d.scale===d.scaleMax&&e.addClass("disabled")):e.add(f).addClass("disabled");break;case a.views.mobileNormalView:var g=a.wrapper.find(".main-container .close");g.css({display:"none"}),c.length>0&&(d.scale>1?g.css({display:"block"}):b.each(a._preventElements,function(b,c){c.off("touchmove",a._prevent),a._preventElements=[]}))}},d.prototype.isZoomed=function(){return this.getZoomSlide().ampZoomInline("state").scale>1},d.prototype.bindTapEvent=function(a,c){function d(a){var b={x:0,y:0};if("touchstart"===a.type||"touchmove"===a.type||"touchend"===a.type||"touchcancel"===a.type){var c=a.originalEvent.touches[0]||a.originalEvent.changedTouches[0];b.x=c.pageX,b.y=c.pageY}else"mousedown"!==a.type&&"mouseup"!==a.type&&"mousemove"!==a.type&&"mouseover"!==a.type&&"mouseout"!==a.type&&"mouseenter"!==a.type&&"mouseleave"!==a.type||(b.x=a.pageX,b.y=a.pageY);return b}var e,f,g=this,h=g.canTouch?"":"mousedown ",i=g.canTouch?"":"mouseup ";this.settings.zoomInlineDoubleTap?(h+=g.doubleTapEvent(a),i+="doubletapend"):(h+="touchstart",i+="touchend"),a.on(h,function(h){var j=b(this);if(3===h.which)return!1;if("progress"!==j.data("startEvent")){j.data("startEvent","progress"),setTimeout(function(){j.data("startEvent","done")},500);this.tap=!0,e=d(h),a.one(i,function(a){if(3===a.which)return!1;var b=this;f=d(a);var g=e.x-f.x,h=e.y-f.y;(Math.abs(g)>=5||Math.abs(h)>=5)&&(b.tap=!1),b.tap&&(b.tap=!1,c.call(b))}),g.isZoomed()&&h.stopPropagation()}})},d.prototype.checkSpins=function(){var a=this,b=a.mainContainerList.find(".spin-trap");a.canTouch?(b.removeClass("active-for-scrolling"),b.parent().off("touchstart",a._prevent)):b.css({display:"none"})},d.prototype.bindIconClickEvent=function(a,c){a.on("click",function(a,d){a.stopPropagation(),b(this).hasClass("disabled")?a.preventDefault():c()})},d.prototype.checkNavContainerNavArrowsStyle=function(){var a=this,b=a.wrapper.find(".nav-container"),c=b.find(".nav-container-prev"),d=b.find(".nav-container-next"),e=b.find(".amp-slide:not(.amp-selected) .mobile-thumbnail").width(),f=(52-e)/2;c.add(d).css("width",e).css("height",e),c.css("left",f),d.css("right",f)},d.prototype.checkMainContainerSlidesVisibility=function(a){if(this.IE){var b=this,c=b.currentAssetIndex,a=a||0;b.videoTimeout&&clearTimeout(b.videoTimeout);var d=b.assets[c],e=b.mainContainerList.find(".amp-slide").has(".video");if(d.hasOwnProperty("media"))return void e.css({opacity:1});b.videoTimeout=setTimeout(function(){e.css({opacity:0})},a)}},d.prototype._prevent=function(a){a.preventDefault()},d.prototype._preventElements=[],a.amp.Viewer=d}(window,jQuery),function(a,b){"use strict";var c={bridge:window.ecommBridge,page:null,setPageInfo:function(a){this.page={};for(var b in a)a.hasOwnProperty(b)&&(this.page[b]=a[b])},enrichMediaListWithParams:function(a,c){return a&&a.constructor===Array&&a.length>0&&b.each(a,function(a,b){for(var d in c)b[d]=c[d]}),a},convertListToSet:function(a,b){for(var c={name:"set",items:[]},d=0;d Date: Thu, 21 Sep 2023 16:10:24 +0200 Subject: [PATCH 60/78] feat: using accelerated media for the blog page --- pages/blog/index.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pages/blog/index.tsx b/pages/blog/index.tsx index a436d42d..c1e6b911 100644 --- a/pages/blog/index.tsx +++ b/pages/blog/index.tsx @@ -9,6 +9,8 @@ import { ProductFacet } from '@components/product'; import { NavigationItem } from '@components/core/Masthead'; import { useAppContext } from '@lib/config/AppContext'; import _ from 'lodash'; +import { useAcceleratedMedia } from '@components/admin/AdminPanel/context/AcceleratedMediaContext'; +import { ImageFormat } from '@utils/getImageURL'; export async function getServerSideProps(context: GetServerSidePropsContext) { const data = await fetchStandardPageData( @@ -38,6 +40,14 @@ export default function Womens({ }; let { algolia, cms } = useAppContext() + + const { + acceleratedMedia + } = useAcceleratedMedia(); + + let format = 'auto' + if (acceleratedMedia) format = ImageFormat.AVIF + useEffect(() => { let { instantsearch, algoliasearch } = window as any; let hub = cms.hub @@ -91,10 +101,10 @@ export default function Womens({
    - - - - ${snippet.title} + + + + ${snippet.title}
    From 31de45d145e6bacca6e497327c5554284fac7e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 16:16:34 +0200 Subject: [PATCH 61/78] fix: using getImageURL to get correct format --- components/cms-modern/CustomRichText/CustomRichText.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/cms-modern/CustomRichText/CustomRichText.tsx b/components/cms-modern/CustomRichText/CustomRichText.tsx index 7bf1a4d8..f7aa5fb1 100644 --- a/components/cms-modern/CustomRichText/CustomRichText.tsx +++ b/components/cms-modern/CustomRichText/CustomRichText.tsx @@ -4,6 +4,7 @@ import ReactMarkdown from 'markdown-to-jsx'; import { ContentBlock } from '@components/cms-modern'; import { Box, Link, Typography } from '@mui/material'; import { nanoid } from 'nanoid' +import { getImageURL } from '@utils/getImageURL'; type Props = { } & CmsContent; @@ -57,7 +58,7 @@ const Text: FC = ({ return ( data && {data.name} From a79aaac2ec9a49793cb6ba62277384ea81e6745e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9za=20Kalfane?= Date: Thu, 21 Sep 2023 16:29:32 +0200 Subject: [PATCH 62/78] fix: using next link for internal links --- components/cms-modern/Navigation/MegaMenu.tsx | 4 +++- components/cms-modern/Store/Store.tsx | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/cms-modern/Navigation/MegaMenu.tsx b/components/cms-modern/Navigation/MegaMenu.tsx index 9a46857f..58921f68 100644 --- a/components/cms-modern/Navigation/MegaMenu.tsx +++ b/components/cms-modern/Navigation/MegaMenu.tsx @@ -44,7 +44,9 @@ const MegaMenu: React.FC = ({
    {children.map((child: any, index: number) =>