├── Demo.framer ├── framer │ ├── version │ ├── .bookmark │ ├── images │ │ ├── cursor.png │ │ ├── icon-120.png │ │ ├── icon-152.png │ │ ├── icon-180.png │ │ ├── icon-192.png │ │ ├── icon-76.png │ │ ├── cursor@2x.png │ │ ├── cursor-active.png │ │ └── cursor-active@2x.png │ ├── config.json │ ├── framer.generated.js │ ├── style.css │ ├── framer.init.js │ ├── framer.vekter.js │ └── framer.modules.js ├── images │ └── .gitkeep ├── .gitignore ├── index.html ├── app.coffee └── modules │ ├── Constraints.coffee │ └── DesignComponents.coffee ├── images ├── Button1.png ├── Card1.png ├── Card2.png ├── Card3.png ├── Sliders.png ├── States1.png ├── States2.png └── cardContent.gif ├── module.json ├── snippet.coffee ├── README.md └── DesignComponents.coffee /Demo.framer/framer/version: -------------------------------------------------------------------------------- 1 | 12 -------------------------------------------------------------------------------- /Demo.framer/images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/Button1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/Button1.png -------------------------------------------------------------------------------- /images/Card1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/Card1.png -------------------------------------------------------------------------------- /images/Card2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/Card2.png -------------------------------------------------------------------------------- /images/Card3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/Card3.png -------------------------------------------------------------------------------- /images/Sliders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/Sliders.png -------------------------------------------------------------------------------- /images/States1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/States1.png -------------------------------------------------------------------------------- /images/States2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/States2.png -------------------------------------------------------------------------------- /images/cardContent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/images/cardContent.gif -------------------------------------------------------------------------------- /Demo.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/.bookmark -------------------------------------------------------------------------------- /Demo.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Demo.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebcglbailey/framer-DesignComponents/HEAD/Demo.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Design Components (Symbols)", 3 | "description": "Create symbols in Framer design mode! A module for converting your designs in design mode into full scalable classes.", 4 | "author": "Sebastian Bailey", 5 | "require": "Design = require 'DesignComponents'", 6 | "install": "DesignComponents.coffee", 7 | "example": "snippet.coffee" 8 | } -------------------------------------------------------------------------------- /Demo.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 667, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 375, 8 | "fullScreen" : false, 9 | "deviceType" : "apple-iphone-8-space-gray", 10 | "sharedPrototype" : 0, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "B5C1B068-5C3B-4653-BF76-A3B804F15F82", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : 0, 18 | "foldedCodeRanges" : [ 19 | "{37, 246}", 20 | "{348, 226}", 21 | "{649, 984}", 22 | "{1681, 381}", 23 | "{2113, 674}" 24 | ], 25 | "deviceScale" : "fit" 26 | } -------------------------------------------------------------------------------- /Demo.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /Demo.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"Demo.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Demo.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Demo.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /snippet.coffee: -------------------------------------------------------------------------------- 1 | # To see a full working demo of the DesignComponent module, please download the demo file at: 2 | 3 | # https://github.com/sebcglbailey/framer-DesignComponents/tree/master/Demo.framer 4 | 5 | # The demo file includes some pre-made components, and shows you how to edit and use the Design Components 6 | 7 | 8 | ### 9 | 10 | --------------------------------------- 11 | REQUIRING THE MODULE 12 | --------------------------------------- 13 | 14 | The usual line of code for requiring the module will be: 15 | 16 | Design = require "DesignComponents" 17 | 18 | ### 19 | 20 | 21 | 22 | ### 23 | 24 | --------------------------------------- 25 | NAMING CONVENTIONS 26 | --------------------------------------- 27 | 28 | For native components: 29 | 30 | Prefix the group of layers with an underscore 31 | 32 | Examples: 33 | _SliderComponent 34 | _RangeSliderComponent 35 | 36 | These will then be accessible within the code view by typing: 37 | 38 | slider = new Design.SliderComponent 39 | rangeSlider = new Design.RangeSliderComponent 40 | 41 | 42 | ------------------- 43 | 44 | 45 | For custom classes: 46 | 47 | Prefix the custom component name with "Custom_" 48 | 49 | Example: 50 | Custom_Card 51 | 52 | This will be built in code using: 53 | 54 | card = new Design.Card 55 | 56 | Child layers are accessible by name on initiating the class, and also after initilisation. 57 | 58 | card = new Design.Card 59 | avatar: 60 | image: "image_url" 61 | title: 62 | text: "Title text here" 63 | 64 | 65 | ------------------- 66 | 67 | To add states to your custom classes: 68 | 69 | Prefix the group name with "State_", and append the name with an event (optional) 70 | To give the state a name, prefix the entire group name again with the name of the state. (optional) 71 | 72 | Examples: 73 | Custom_Button 74 | Custom_Input 75 | Custom_Emoji 76 | 77 | State_Button_MouseDown 78 | Success_State_Input_Tap 79 | Error_State_Input_Tap 80 | Congrats_State_Emoji 81 | 82 | ### -------------------------------------------------------------------------------- /Demo.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Demo.framer/app.coffee: -------------------------------------------------------------------------------- 1 | Design = require "DesignComponents" 2 | 3 | # DEMO SETUP 4 | 5 | Layer.select(".UIKit").x = Screen.width 6 | 7 | Screen.backgroundColor = "#886AE2" 8 | 9 | scroll = new ScrollComponent 10 | size: Screen 11 | scrollHorizontal: false 12 | mouseWheelEnabled: true 13 | mouseWheelSpeedMultiplier: 0.125 14 | scroll.content.clip = false 15 | 16 | 17 | 18 | 19 | 20 | 21 | # Designing sliders in the design tab, and using the class 22 | # SLIDERS - NATIVE COMPONENTS 23 | 24 | slider = new Design.SliderComponent 25 | parent: scroll.content 26 | y: 50 27 | x: Align.center 28 | 29 | 30 | 31 | rangeSlider = new Design.RangeSliderComponent 32 | parent: scroll.content 33 | y: slider.maxY + 75 34 | x: Align.center 35 | 36 | # Designing a custom component in the design tab, and using it as a class 37 | # CARDS - CUSTOM CLASS 38 | 39 | # Recreate the card without editing the content 40 | card1 = new Design.Card 41 | parent: scroll.content 42 | name: "card1" 43 | y: rangeSlider.maxY + 50 44 | 45 | 46 | # Recreate the card and edit the content 47 | card2 = new Design.Card 48 | parent: scroll.content 49 | name: "card2" 50 | y: card1.maxY + 10 51 | avatar: 52 | borderRadius: 0 53 | image: Utils.randomImage() 54 | subheader: 55 | text: "This is a new subheader" 56 | content: 57 | text: "This is some content that has changed" 58 | 59 | 60 | # Recreate the card, edit the content, and apply some constraints to the child layers 61 | card3 = new Design.Card 62 | parent: scroll.content 63 | name: "card3" 64 | y: card2.maxY + 10 65 | avatar: 66 | borderRadius: 0 67 | image: Utils.randomImage() 68 | subheader: 69 | text: "Lorem ipsum" 70 | content: 71 | constraints: 72 | pushDown: true 73 | 74 | textString = "This is a string that can type itself\nTo show it animating over multiple lines\nWhich is really cool!" 75 | 76 | for i in [0..textString.length] 77 | do (i) -> 78 | Utils.delay i*0.1, -> 79 | card3.content.text = textString.slice 0, i 80 | 81 | # Using states on a custom class to add events 82 | # # STATES WITH CUSTOM CLASSES 83 | 84 | # # Button will have a "MouseDown" and "MouseUp" event listener 85 | button = new Design.Button 86 | parent: scroll.content 87 | name: "button" 88 | y: card3.maxY + 50 89 | x: Align.center 90 | 91 | # # # Toggle will have multiple states that it will cycle through on "Tap" 92 | toggle = new Design.Toggle 93 | parent: scroll.content 94 | name: "toggle" 95 | y: button.maxY + 50 96 | x: Align.center 97 | 98 | # Using states on a custom class without an event 99 | # STATES WITHOUT AN EVENT LISTENER 100 | 101 | 102 | # Setting the state upon initilisation 103 | emoji = new Design.Emoji 104 | parent: scroll.content 105 | y: toggle.maxY + 50 106 | x: Align.center 107 | state: "Angel" 108 | 109 | # Setting a state after initilisation 110 | emoji.state = "Wink" 111 | emoji.state = Utils.randomChoice ["Smile", "Angel", "Wink", "Unamused"] 112 | 113 | # # Animating between states 114 | emoji.onTap -> 115 | currentState = @states.current.name 116 | 117 | if currentState == "default" || currentState == "Smile" 118 | @animateState "Wink", true 119 | else if currentState == "Wink" 120 | @animateState "Angel", true 121 | else if currentState == "Angel" 122 | @animateState "Unamused", true 123 | else if currentState == "Unamused" 124 | @animateState "Smile", true 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # framer-DesignComponents 2 | A module for converting your designs in design mode into full scalable classes. 3 | 4 | **Supported native components:** 5 | 6 | * SliderComponent 7 | * RangeSliderComponent 8 | 9 | 10 | ### Links 11 | 12 | * [Installation](#installation) 13 | * [Native components](#native-components) 14 | * [Custom classes](#custom-classes) 15 | * [Constraints](#constraints) 16 | * [States](#states) 17 | 18 | 19 | ## Installation 20 | 21 | ### Automatic installation with [Framer Modules](https://www.framermodules.com/) 22 | 23 | 24 | Install with Framer Modules 26 | 27 | 28 | ### Manual installation 29 | 30 | Download and move the Constraints.coffee and DesignComponents.coffee files to your modules folder. 31 | 32 | At the top of your file, place this line of code: 33 | 34 | ```coffeescript 35 | Design = require "DesignComponents" 36 | ``` 37 | 38 | Done! That is all the code you need to do to get this module started. Now onto the fun stuff. 39 | 40 | 41 | 42 | ## Native components 43 | 44 | For the native slider components, all you need to do is design a slider with the correct child names inside, and prefix the whole group with an _. 45 | 46 | For example the layer structure will look like this: 47 | 48 | ![Layer List](images/Sliders.png) 49 | 50 | The _SliderComponent or _RangeSliderComponent layers are the background fill for the slider. 51 | 52 | 53 | ## Custom classes 54 | 55 | A custom class will be generated from your design, *including all of the layer's children*. You will then be able to add this class as many times as you want in the code view, without having to declare a class extension and constructor. 56 | 57 | To create a custom class in design mode, simply name the layer in design mode with the following syntax: 58 | 59 | ``` 60 | Custom_{className} 61 | ``` 62 | 63 | where {className} is replaced by the name of your class. 64 | 65 | For example: 66 | 67 | ![Custom Button](images/Button1.png) 68 | ![Custom Card](images/Card1.png) 69 | 70 | **Note:** You *do not* have to create a target for these layers. 71 | 72 | 73 | ### Using your class in your prototype 74 | 75 | To add the class to your prototype, simply create a new instance of the class as you would a layer: 76 | 77 | ```coffeescript 78 | button = new Design.Button 79 | 80 | card = new Design.Card 81 | ``` 82 | 83 | **The layers within your class are also accessible within the the creation of the new instance, and oyu can change their properties as oyu would any other layer in code.** 84 | 85 | #### Card structure in Design mode 86 | 87 | ![Custom Card](images/Card2.png) 88 | 89 | > **IMPORTANT:** Any SVG Layer in Design mode **must** be wrapped inside of a frame for this module to work. 90 | 91 | #### Editing the contents of the class in code 92 | 93 | ```coffeescript 94 | card = new Design.Card 95 | avatar: 96 | borderRadius: 0 97 | image: Utils.randomImage() 98 | subheader: 99 | text: "This is a new subheader" 100 | content: 101 | text: "This is some content that has changed" 102 | ``` 103 | 104 | ![Edited Card](images/Card3.png) 105 | 106 | 107 | ## Constraints 108 | 109 | With this module comes the ability to set constraints to your layers in code as well as design. 110 | 111 | When oyu initiate an instance of your symbol, it will automatically copy over the constraints of the design layer, but you are now able to override these upon initialisation, and later. 112 | 113 | ### Setting constraints on a new layer 114 | 115 | #### Arguments 116 | 117 | * top – the distance of the top edge from the top of the parent layer. 118 | * left – the distance of the left edge from the left of the parent layer. 119 | * bottom – the distance of the bottom edge from the bottom of the parent layer. 120 | * right – the distance of the right edge from the right of the parent layer. 121 | * centerX – the position of the layer within its parent on horizontal axis as a ratio between 0 - 1. 122 | * centerY – the position of the layer within its parent on the vertical axis as a ratio between 0 - 1. 123 | * scaleX – the width of the layer relative to its parent width as a ratio between 0 - 1. 124 | * scaleY – the height of the layer relative to its parent height as a ratio between 0 - 1. 125 | * aspectRatioLocked – the original ratio of width/height of the layer stays the same if set to true. 126 | * pushDown – If you want the layer to resize its parent when it resizes or moves, keeping the same original margin. I.e. when you add multiple lines to a text layer. NOTE: The layer cannot have a bottom constraint set for this to work. 127 | * pushRight – The same as pushDown but with the width of the parent. NOTE: The layer cannot have a right constraints set for this to work. 128 | 129 | ```coffeescript 130 | layer = new Layer 131 | size: 50 132 | 133 | layer.constraints = 134 | top: null 135 | left: 20 136 | bottom: null 137 | right: 20 138 | centerX: null 139 | centerY: 0.5 140 | scaleX: null 141 | scaleY: 0.8 142 | aspectRatioLocked: true 143 | pushDown: true 144 | pushRight: null 145 | ``` 146 | 147 | 148 | ### Setting constraints on a layer within a custom class 149 | 150 | If you are using a custom class from the Design mode, you can set the constraints upon initilisation. 151 | 152 | ```coffeescript 153 | card = new Design.Card 154 | constraints: 155 | left: 10 156 | right: 10 157 | avatar: 158 | image: Utils.randomImage() 159 | constraints: 160 | right: 15 161 | top: 15 162 | aspectRatioLocked: true 163 | content: 164 | text: "Lorem ipsum dolor sit amet.\nNew content\nMore new content" 165 | constraints: 166 | pushDown: true 167 | ``` 168 | 169 | See it in action: 170 | 171 | ![Card Expand Gif](images/cardContent.gif) 172 | 173 | 174 | 175 | ## States 176 | 177 | ### Single states 178 | 179 | The syntax for adding a single state on an event is: 180 | 181 | ``` 182 | State_{className}_{event} 183 | ``` 184 | 185 | eg: 186 | 187 | ![Single state](images/States1.png) 188 | 189 | ### Multiple states 190 | 191 | Adding multiple states for a event (toggling): 192 | 193 | ``` 194 | {stateName}_State_{className}_{event} 195 | ``` 196 | 197 | eg: 198 | 199 | ![Multiple states](images/States2.png) 200 | 201 | This will automatically add a switch event to the layer to switch the properties of the layer and all of its children upon the triggering of the event. 202 | 203 | ### Animating states 204 | 205 | By default, the design states will not animate between each other. To add default animation options to the events, simply append _Animate to the end of the layer name. 206 | 207 | **For example:** 208 | 209 | ```coffeescript 210 | {stateName}_State_{className}_{eventName}_Animate 211 | ``` 212 | 213 | With your custom classes, there is a new animate function. This will enable the class to animate itself, and all of its descendants at the same time. 214 | 215 | ```coffeescript 216 | animateState(stateName, animate, options) 217 | ``` 218 | 219 | #### Arguments 220 | 221 | * stateName – the name of the state to animate to. 222 | * animate – A boolean, set to override the default animation option for the class. (Optional) 223 | * options – animation options. (Optional) 224 | 225 | ```coffeescript 226 | layer = new Design.Class 227 | 228 | layer.animateState "Error", 229 | time: 1 230 | curve: Spring(damping: 0.8) 231 | ``` 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Demo.framer/modules/Constraints.coffee: -------------------------------------------------------------------------------- 1 | 2 | moveFromRef = (layer, reference, moveRef, layerRef, refType) -> 3 | 4 | originalConstraints = layer.constraintValues 5 | 6 | originalRefValue = reference[layerRef] 7 | originalLayerValue = layer[moveRef] 8 | 9 | layer[moveRef] = reference[layerRef] + layer.constraintValues[refType].value 10 | 11 | # reference.onChange layerRef, (value) -> 12 | # layer[moveRef] = originalLayerValue + (value - originalRefValue) 13 | 14 | layer.constraintValues = originalConstraints 15 | 16 | 17 | pushParent = (layer, direction) -> 18 | 19 | if direction == "down" 20 | originalY = layer.y 21 | originalHeight = layer.height 22 | 23 | layer.onChange "y", (value) -> 24 | @parent.height += value - originalY 25 | originalY = value 26 | originalHeight = @height 27 | layer.onChange "height", (value) -> 28 | @parent.height += value - originalHeight 29 | originalY = @y 30 | originalHeight = value 31 | 32 | if direction == "right" 33 | originalX = layer.x 34 | originalWidth - layer.width 35 | 36 | layer.onChange "x", (value) -> 37 | @parent.width += value - originalX 38 | originalX = value 39 | originalWidth = @width 40 | layer.onChange "width", (value) -> 41 | @parent.width += value - originalWidth 42 | originalX = @x 43 | originalWidth = value 44 | 45 | 46 | addReferenceEvents = (layer) -> 47 | 48 | originalConstraints = layer.constraintValues 49 | 50 | if layer.constraintValues?.topRef?.layer? || layer.constraintValues?.bottomRef?.layer? 51 | 52 | reference = layer.constraintValues?.topRef?.layer || layer.constraintValues?.bottomRef?.layer 53 | 54 | originalYRef = reference.y 55 | originalHeightRef = reference.height 56 | originalY = layer.y 57 | 58 | reference.onChange "y", (value) -> 59 | layer.y = originalY + (value - originalYRef) 60 | originalYRef = value 61 | originalY = layer.y 62 | 63 | unless layer.constraintValues?.topRef?.align == "y" 64 | reference.onChange "height", (value) -> 65 | layer.y = originalY + (value - originalHeightRef) 66 | originalHeightRef = value 67 | originalY = layer.y 68 | 69 | if layer.constraintValues?.topRef? && layer.constraintValues?.bottomRef? 70 | reference.onChange "height", (value) -> 71 | layer.height = value - layer.constraintValues?.topRef.value - layer.constraintValues?.bottomRef.value 72 | layer.y = reference.y + layer.constraintValues?.topRef.value 73 | originalHeightRef = value 74 | 75 | if layer.constraintValues?.leftRef?.layer? || layer.constraintValues?.rightRef?.layer? 76 | reference = layer.constraintValues?.leftRef?.layer || layer.constraintValues?.rightRef?.layer 77 | 78 | originalXRef = reference.x 79 | originalWidthRef = reference.width 80 | originalX = layer.x 81 | 82 | reference.onChange "x", (value) -> 83 | layer.x = originalX + (value - originalXRef) 84 | originalXRef = value 85 | originalX = layer.x 86 | 87 | unless layer.constraintValues?.left?.align == "x" 88 | reference.onChange "width", (value) -> 89 | layer.x = originalX + (value - originalWidthRef) 90 | originalWidthRef = value 91 | originalX = layer.x 92 | 93 | if layer.constraintValues?.leftRef? && layer.constraintValues?.rightRef? 94 | reference.onChange "width", (value) -> 95 | layer.width = value - layer.constraintValues?.leftRef.value - layer.constraintValues?.rightRef.value 96 | layer.x = reference.x + layer.constraintValues?.leftRef.value 97 | originalWidthRef = value 98 | 99 | 100 | buildConstraintsProtos = (constructorName) -> 101 | 102 | constructorName = eval constructorName 103 | 104 | constructorName::setConstraints = (options={}, origin) -> 105 | 106 | @constraintValues = 107 | top: if typeof options.top == "object" then null else if options.top? then options.top else if origin?.constraintValues? then origin.constraintValues.top else null 108 | left: if typeof options.left == "object" then null else if options.left? then options.left else if origin?.constraintValues? then origin.constraintValues.left else null 109 | bottom: if typeof options.bottom == "object" then null else if options.pushDown then null else if options.bottom? then options.bottom else if origin?.constraintValues? then origin.constraintValues.bottom else null 110 | right: if typeof options.right == "object" then null else if options.pushRight then null else if options.right? then options.right else if origin?.constraintValues? then origin.constraintValues.right else null 111 | width: @width 112 | height: @height 113 | widthFactor: if options.scaleX? then options.scaleX else if options.widthFactor? then options.widthFactor else null 114 | heightFactor: if options.scaleY? then options.scaleY else if options.heightFactor? then options.heightFactor else null 115 | centerAnchorX: if options.centerX? then options.centerX else if options.centerAnchorX? then options.centerAnchorX else null 116 | centerAnchorY: if options.centerY? then options.centerY else if options.centerAnchorY? then options.centerAnchorY else null 117 | aspectRatioLocked: if options.aspectRatioLocked? then options.aspectRatioLocked else if origin?.constraintValues then origin.constraintValues.aspectRatioLocked else false 118 | 119 | # resets 120 | values = @constraintValues 121 | if values.top? && values.bottom? 122 | @constraintValues.heightFactor = null 123 | @constraintValues.centerAnchorY = null 124 | if values.left? && values.right? 125 | @constraintValues.widthFactor = null 126 | @constraintValues.centerAnchorX = null 127 | if values.left? && values.right? && values.top? && values.bottom? 128 | @constraintValues.aspectRatioLocked = false 129 | 130 | for ref in [["top", "y", "maxY", "topRef", "bottom"], ["left", "x", "maxX", "leftRef", "right"], ["bottom", "maxY", "y", "bottomRef", "top"], ["right", "maxX", "x", "rightRef", "left"]] 131 | 132 | if typeof options[ref[0]] == "object" && options[ref[0]] != null && !options[ref[3]]? 133 | 134 | if options[ref[0]].layer? 135 | if @parent? && @parent.selectChild(options[ref[0]].layer)? 136 | layer = @parent.selectChild options[ref[0]].layer 137 | else 138 | layer = Layer.select options[ref[0]].layer 139 | else layer = @parent 140 | 141 | align = null 142 | 143 | if !options[ref[0]].value? && layer == @parent 144 | value = @[ref[1]] 145 | else if options[ref[0]].align? && options[ref[0]].value? 146 | value = options[ref[0]].value 147 | align = options[ref[0]].align 148 | else if options[ref[0]].align? 149 | value = 0 150 | align = options[ref[0]].align 151 | else if !options[ref[0]].value? && !options[ref[0]].align? 152 | value = @[ref[1]] - layer[ref[2]] 153 | align = ref[4] 154 | else 155 | value = options[ref[0]].value 156 | align = ref[4] 157 | 158 | if align == "left" then align = "x" 159 | else if align == "right" then align = "maxX" 160 | else if align == "top" then align = "y" 161 | else if align == "bottom" then align = "maxY" 162 | 163 | @constraintValues[ref[3]] = 164 | layer: layer 165 | value: value 166 | align: align 167 | 168 | @constraintValues[ref[0]] = null 169 | @constraintValues[ref[4]] = null 170 | 171 | # moveFromRef @, layer, ref[1], ref[2], ref[3] 172 | 173 | if options.pushDown? 174 | @constraintValues.bottom = null 175 | pushParent @, "down" 176 | if options.pushRight? 177 | @constraintValues.right = null 178 | pushParent @, "right" 179 | 180 | unless options.pushDown || @constraintValues.topRef || @constraintValues.bottomRef 181 | @constraintValues.bottom = if options.bottom? then options.bottom else if origin?.constraintValues? then origin.constraintValues.bottom else null 182 | unless options.pushRight || @constraintValues.leftRef || @constraintValues.rightRef 183 | @constraintValues.right = if options.right? then options.right else if origin?.constraintValues? then origin.constraintValues.right else null 184 | 185 | if @constraintValues.top == null && @constraintValues.bottom == null && @constraintValues.centerAnchorY == null && !@constraintValues.topRef && !@constraintValues.bottomRef 186 | @constraintValues.top = @y 187 | if @constraintValues.left == null && @constraintValues.right == null && @constraintValues.centerAnchorX == null && !@constraintValues.leftRef && !@constraintValues.rightRef 188 | @constraintValues.left = @x 189 | 190 | @applyConstraints() 191 | 192 | 193 | constructorName::applyConstraints = -> 194 | 195 | return if !@constraintValues 196 | 197 | values = @constraintValues 198 | 199 | if !@parent then parent = Screen else parent = @parent 200 | 201 | aspectRatio = @width / @height 202 | 203 | # position 204 | if values.top? && typeof values.top != "object" 205 | @y = values.top 206 | else if values.top == null && values.topRef?.layer? 207 | @y = values.topRef.layer[values.topRef.align] + values.topRef.value 208 | 209 | if values.left? && typeof values.left != "object" 210 | @x = values.left 211 | else if values.left == null && values.leftRef?.layer? 212 | @x = values.leftRef.layer[values.leftRef.align] + values.leftRef.value 213 | 214 | # size 215 | if values.left? && values.right? 216 | @width = parent.width - @x - values.right 217 | if values.aspectRatioLocked 218 | @height = @width / aspectRatio 219 | if values.top? && values.bottom? 220 | @height = parent.height - @y - values.bottom 221 | if values.aspectRatioLocked 222 | @width = @height * aspectRatio 223 | 224 | # if values.leftRef? && values.rightRef? 225 | # @width = parent.width - values.leftRef.value - values.rightRef.value 226 | # if values.topRef? && values.bottomRef? 227 | # @height = parent.height - values.topRef.value - values.bottomRef.value 228 | 229 | if values.widthFactor? 230 | @width = parent.width * values.widthFactor 231 | if values.heightFactor? 232 | @height = parent.height * values.heightFactor 233 | 234 | # max position 235 | if values.right? 236 | @maxX = parent.width - values.right 237 | else if values.right == null && values.rightRef?.layer? 238 | @maxX = values.rightRef.layer[values.rightRef.align] - values.rightRef.value 239 | if values.bottom? 240 | @maxY = parent.height - values.bottom 241 | else if values.bottom == null && values.bottomRef?.layer? 242 | @maxY = values.bottomRef.layer[values.bottomRef.align] - values.bottomRef.value 243 | 244 | # center position 245 | if !values.left? && !values.right? && values.centerAnchorX? 246 | @midX = parent.width * values.centerAnchorX 247 | if !values.top? && !values.bottom? && values.centerAnchorY? 248 | @midY = parent.height * values.centerAnchorY 249 | 250 | @constraintValues = values 251 | 252 | addReferenceEvents(@) 253 | 254 | 255 | layerTypes = ["Layer", "TextLayer", "ScrollComponent", "PageComponent", "SliderComponent", "RangeSliderComponent", "SVGLayer", "BackgroundLayer", "SVGPath", "SVGGroup"] 256 | for type in layerTypes 257 | buildConstraintsProtos(type) 258 | 259 | 260 | 261 | Object.defineProperty(Layer.prototype, "constraints", { 262 | 263 | get: -> return @_constraints 264 | set: (value) -> 265 | @_constraints = value 266 | @emit "change:constraints", value 267 | @setConstraints value 268 | 269 | }) -------------------------------------------------------------------------------- /DesignComponents.coffee: -------------------------------------------------------------------------------- 1 | 2 | ### 3 | ------------------ 4 | CUSTOM CLASSES 5 | ------------------ 6 | ### 7 | 8 | kit = Layer.select "*UIKit*" 9 | if kit? then kit.x = Screen.width * 1000; kit.name = ".UIKit" 10 | 11 | for layer in Layer.selectAll "@*" 12 | parent = layer.parent 13 | name = layer.name.replace "@", "" 14 | parent[name] = layer 15 | 16 | customComponents = Layer.selectAll "Custom_*" 17 | 18 | Layer::addDesignChildren = (origin) -> 19 | if !origin? then origin = @ 20 | for child in origin.selectAllChildren ("*") 21 | parent = child.parent 22 | parent[child.name] = child 23 | 24 | 25 | stateChangeProps = [ 26 | "width", "height", 27 | "opacity", 28 | "scaleX", "scaleY", "scaleZ", "scale", 29 | "skewX", "skewY", "skew", 30 | "rotationX", "rotationY", "rotationZ", "rotation", 31 | "blur", 32 | "brightness", "saturate", "hueRotate", "contrast", "invert", "grayscale", "sepia", "blending", 33 | "backgroundBlur", "backgroundBrightness", "backgroundSaturate", "backgroundHueRotate", "backgroundContrast", "backgroundInvert", "backgroundGrayscale", "backgroundSepia", 34 | "shadow1", "shadow2", "shadow3", "shadow4", "shadow5", "shadow6", "shadow7", "shadow8", "shadow9", 35 | "shadowX", "shadowY", "shadowBlur", "shadowSpread", "shadowColor", "shadowType", 36 | "shadows", 37 | "backgroundColor", "color", 38 | "borderRadius", "borderColor", "borderWidth", "borderStyle", 39 | "image", "gradient", 40 | "text", 41 | "fill", "stroke", "strokeWidth", "strokeWidthMultiplier" 42 | ] 43 | 44 | 45 | pushParent = (layer, direction) -> 46 | layer.pushValues = 47 | marginBottom: layer.parent.height - layer.maxY 48 | marginRight: layer.parent.width - layer.maxX 49 | 50 | if direction == "down" 51 | layer.onChange "y", -> 52 | @parent.height = layer.maxY + @pushValues.marginBottom 53 | layer.onChange "height", -> 54 | @parent.height = layer.maxY + @pushValues.marginBottom 55 | 56 | buildConstraintsProtos = (constructorName) -> 57 | 58 | constructorName = eval constructorName 59 | 60 | constructorName::setConstraints = (options={}, origin) -> 61 | @constraintValues = 62 | top: if typeof options?.top == "object" then null else if options?.top? && typeof options.top == "number" then options.top else origin?.constraintValues?.top || null 63 | left: if typeof options?.left == "object" then null else if options?.left? && typeof options.top == "number" then options.top else origin?.constraintValues?.left || null 64 | bottom: if typeof options?.bottom == "object" then null else if options?.pushDown then null else if options?.bottom? && typeof options.bottom == "number" then options.bottom else origin?.constraintValues?.bottom || null 65 | right: if typeof options?.right == "object" then null else if options?.pushRight then null else if options?.right? && typeof options.right == "number" then options.right else origin?.constraintValues?.right || null 66 | width: @width 67 | height: @height 68 | widthFactor: options?.scaleX || options?.widthFactor || null 69 | heightFactor: options?.scaleY ||options?.heightFactor || null 70 | centerAnchorX: options?.centerX || options?.centerAnchorX || null 71 | centerAnchorY: options?.centerY || options?.centerAnchorY || null 72 | aspectRatioLocked: if options?.aspectRatioLocked? then options.aspectRatioLocked else if origin?.constraintValues?.aspectRatioLocked? then origin.constraintValues.aspectRatioLocked else false 73 | 74 | if options.pushDown? 75 | @constraintValues.bottom = null 76 | pushParent @, "down" 77 | if options.pushRight? 78 | @constraintValues.right = null 79 | pushParent @, "right" 80 | 81 | constraints = @constraintValues 82 | textLayerAutoSize = typeof @ == TextLayer && @autoSize 83 | 84 | @onChange "y", -> 85 | @constraintValues = constraints 86 | @onChange "x", -> 87 | @constraintValues = constraints 88 | @onChange "height", -> 89 | @constraintValues = constraints 90 | @onChange "width", -> 91 | @constraintValues = constraints 92 | 93 | @applyConstraints() 94 | 95 | constructorName::applyConstraints = -> 96 | 97 | return if !@constraintValues 98 | 99 | values = @constraintValues 100 | 101 | if !@parent then parent = Screen else parent = @parent 102 | 103 | aspectRatio = @width / @height 104 | 105 | # position 106 | if values.top? && typeof values.top != "object" 107 | @y = values.top 108 | else if values.top == null && values.topRef?.layer? 109 | @y = values.topRef.layer[values.topRef.align] + values.topRef.value 110 | 111 | if values.left? && typeof values.left != "object" 112 | @x = values.left 113 | else if values.left == null && values.leftRef?.layer? 114 | @x = values.leftRef.layer[values.leftRef.align] + values.leftRef.value 115 | 116 | # size 117 | if values.left? && values.right? 118 | @width = parent.width - @x - values.right 119 | if values.aspectRatioLocked 120 | @height = @width / aspectRatio 121 | if values.top? && values.bottom? 122 | @height = parent.height - @y - values.bottom 123 | if values.aspectRatioLocked 124 | @width = @height * aspectRatio 125 | 126 | if values.widthFactor? 127 | @width = parent.width * values.widthFactor 128 | if values.heightFactor? 129 | @height = parent.height * values.heightFactor 130 | 131 | # max position 132 | if values.right? 133 | @maxX = parent.width - values.right 134 | else if values.right == null && values.rightRef?.layer? 135 | @maxX = values.rightRef.layer[values.rightRef.align] - values.rightRef.value 136 | if values.bottom? 137 | @maxY = parent.height - values.bottom 138 | else if values.bottom == null && values.bottomRef?.layer? 139 | @maxY = values.bottomRef.layer[values.bottomRef.align] - values.bottomRef.value 140 | 141 | # center position 142 | if !values.left? && !values.right? && values.centerAnchorX? 143 | @midX = parent.width * values.centerAnchorX 144 | if !values.top? && !values.bottom? && values.centerAnchorY? 145 | @midY = parent.height * values.centerAnchorY 146 | 147 | @constraintValues = values 148 | 149 | 150 | layerTypes = ["Layer", "TextLayer", "ScrollComponent", "PageComponent", "SliderComponent", "RangeSliderComponent", "SVGLayer", "BackgroundLayer", "SVGPath", "SVGGroup"] 151 | for type in layerTypes 152 | buildConstraintsProtos(type) 153 | 154 | Object.defineProperty(Layer.prototype, "constraints", { 155 | get: -> return @constraintValues 156 | set: (value) -> 157 | @_constraints = value 158 | @emit "change:constraints", value 159 | @setConstraints value 160 | }) 161 | 162 | for component in customComponents 163 | name = component.name.replace "Custom_", "" 164 | 165 | do (component, name) -> 166 | class exports[name] extends Layer 167 | constructor: (@options={}) -> 168 | super @options 169 | @props = Object.assign component.props, {parent: @options.parent || null} 170 | 171 | if @options.constraints? 172 | @constraints = @options.constraints 173 | @props = @options 174 | 175 | @addChildren() 176 | @assignChildren() 177 | @setDescendantProps() 178 | @setDescendantConstraints() 179 | 180 | @stateComponents = Layer.selectAll "*State_#{name}*" 181 | @addStates() 182 | 183 | if @options.state? 184 | @animateState @options.state, false 185 | 186 | addChildren: -> 187 | newParent = component.copy() 188 | for child in newParent.children 189 | if child instanceof SVGPath or child instanceof SVGGroup 190 | Utils.throwInStudioOrWarnInProduction "SVG '#{child.name}' in 'Custom_#{name}' must be wrapped in a Frame in order to create a Design Component Symbol" 191 | else 192 | child.parent = @ 193 | if child instanceof TextLayer && component.selectChild(child.name)? 194 | child.autoSize = true 195 | newParent.destroy() 196 | 197 | assignChildren: -> 198 | for descendant in @descendants 199 | @[descendant.name] = descendant 200 | 201 | setDescendantProps: -> 202 | for descendant in @descendants 203 | do (descendant) => 204 | if @options[descendant.name] 205 | @[descendant.name].constraints = @options[descendant.name].constraints || undefined 206 | @[descendant.name].props = @options[descendant.name] 207 | 208 | setDescendantConstraints: -> 209 | for descendant in @descendants 210 | decName = descendant.name 211 | origin = component.selectChild decName 212 | descendant.setConstraints( 213 | @options[decName]?.constraints || {}, 214 | origin 215 | ) 216 | 217 | addStates: -> 218 | @customStates = 219 | array: [] 220 | 221 | for state in @stateComponents 222 | do (state) => 223 | stateIndex = state.name.indexOf "State" 224 | if stateIndex > 0 225 | stateName = state.name.slice 0, stateIndex-1 226 | else 227 | stateName = state.name.split("State_#{name}_")[1] 228 | 229 | @customStates[stateName] = {} 230 | @customStates.array.push stateName 231 | 232 | addProps = (layer, origin) -> 233 | stateProps = {} 234 | for prop in stateChangeProps 235 | stateProps[prop] = origin[prop] 236 | 237 | if origin instanceof SVGLayer 238 | split1 = origin['html'].split(/opacity/)[1] 239 | if (split1[0] != ':') 240 | split2 = split1.split(/"/)[1] 241 | stateProps['opacity'] = split2 242 | else 243 | stateProps['opacity'] = "1.0" 244 | 245 | layer.states[stateName] = stateProps 246 | 247 | addProps @, state 248 | 249 | for descendant in state.descendants 250 | do (descendant) => 251 | addProps @[descendant.name], descendant 252 | if descendant instanceof SVGPath 253 | addProps @[descendant.name].parent._children[0], descendant.parent._children[0] 254 | 255 | @addStateEvents() 256 | 257 | addStateEvents: -> 258 | events = [] 259 | 260 | for state in @stateComponents 261 | if state.name.includes "_State_#{name}" 262 | stateName = state.name.split("_State_#{name}")[0] 263 | eventName = state.name.split("_State_#{name}")[1] 264 | else 265 | eventName = state.name.replace "State_#{name}_", "" 266 | stateName = eventName 267 | 268 | if eventName.includes "_Animate" 269 | animate = true 270 | eventName = eventName.split("_Animate")[0] 271 | else animate = false 272 | 273 | eventName = eventName.replace "_", "" 274 | 275 | @customStates[stateName].animate = animate 276 | 277 | unless events.includes eventName then events.push eventName 278 | 279 | for eventName in events 280 | 281 | do (eventName) => 282 | 283 | if Events[eventName]? && @customStates.array.includes eventName 284 | 285 | @on Events[eventName], (event, layer) -> 286 | 287 | animateBool = @customStates[eventName].animate 288 | 289 | @stateSwitch(eventName, {animate: animateBool}) 290 | @animateChildren() 291 | 292 | else if Events[eventName]? 293 | 294 | @on Events[eventName], -> 295 | currentIndex = @customStates.array.indexOf(@states.current.name) 296 | nextIndex = currentIndex + 1 297 | if nextIndex == @customStates.array.length then nextIndex = 0 298 | animateBool = @customStates[@customStates.array[nextIndex]].animate 299 | nextState = @customStates.array[nextIndex] 300 | 301 | @stateSwitch(nextState, {animate: animateBool}) 302 | @animateChildren() 303 | 304 | animateChildren: (stateName, animate, options={}) -> 305 | unless stateName? then stateName = @states.current.name 306 | unless animate? then animate = @customStates[stateName].animate 307 | if !animate then options.time = 0 308 | for dec in @descendants 309 | do (dec) => 310 | if dec instanceof SVGPath 311 | # dec.stateSwitch(stateName, {animate: animate, options: options}) 312 | 313 | dec.parent._children[0].stateSwitch(stateName, {animate: animate, options: options}) 314 | else 315 | dec.stateSwitch(stateName, {animate: animate, options: options}) 316 | 317 | animateState: (state, animate, options={}) -> 318 | 319 | if !state? || !@customStates?[state]? then return 320 | if !animate? && @customStates?[state]? then animate = @customStates[state].animate else if animate? then animate = animate else animate = false 321 | if !animate then options.time = 0 322 | 323 | @stateSwitch(state, {animate: animate, options: options}) 324 | @animateChildren(state, animate, options) 325 | 326 | @define "state", 327 | get: -> @options.state 328 | set: (value) -> 329 | @options.state = value 330 | @emit("change:state", @options.state) 331 | @animateState value 332 | 333 | 334 | 335 | customStates = Layer.selectAll "State_*" 336 | 337 | for componentState in customStates 338 | 339 | classEventName = componentState.name.replace "State_", "" 340 | if classEventName.includes "_" 341 | className = classEventName.split("_")[0] 342 | eventName = classEventName.split("_")[1] 343 | else 344 | className = classEventName 345 | 346 | 347 | ### 348 | ------------------ 349 | EXISTING CLASSES 350 | ------------------ 351 | ### 352 | 353 | 354 | components = Layer.selectAll "_*" 355 | 356 | extendSlider = (origin) -> 357 | class exports.SliderComponent extends SliderComponent 358 | 359 | constructor: (@options={}) -> 360 | super @options 361 | 362 | @knob.props = 363 | shadows: origin.knob.shadows 364 | backgroundColor: origin.knob.backgroundColor 365 | borderRadius: origin.knob.borderRadius 366 | frame: origin.knob.frame 367 | 368 | @fill.props = 369 | shadows: origin.fill.shadows 370 | backgroundColor: origin.fill.backgroundColor 371 | borderRadius: origin.fill.borderRadius 372 | frame: origin.fill.frame 373 | 374 | @props = 375 | shadows: origin.shadows 376 | backgroundColor: origin.backgroundColor 377 | borderRadius: origin.borderRadius 378 | size: origin.size 379 | 380 | @value = Utils.modulate origin.knob.midX, [0, origin.width], [@min, @max] 381 | 382 | 383 | extendRangeSlider = (origin) -> 384 | class exports.RangeSliderComponent extends RangeSliderComponent 385 | 386 | constructor: (@options={}) -> 387 | super @options 388 | 389 | @minKnob.props = 390 | shadows: origin.minKnob.shadows 391 | backgroundColor: origin.minKnob.backgroundColor 392 | borderRadius: origin.minKnob.borderRadius 393 | frame: origin.minKnob.frame 394 | @maxKnob.props = 395 | shadows: origin.maxKnob.shadows 396 | backgroundColor: origin.maxKnob.backgroundColor 397 | borderRadius: origin.maxKnob.borderRadius 398 | frame: origin.maxKnob.frame 399 | 400 | @fill.props = 401 | shadows: origin.fill.shadows 402 | backgroundColor: origin.fill.backgroundColor 403 | borderRadius: origin.fill.borderRadius 404 | frame: origin.fill.frame 405 | 406 | @props = 407 | shadows: origin.shadows 408 | backgroundColor: origin.backgroundColor 409 | borderRadius: origin.borderRadius 410 | size: origin.size 411 | 412 | @minValue = Utils.modulate origin.minKnob.midX, [0, origin.width], [@min, @max] 413 | @maxValue = Utils.modulate origin.maxKnob.midX, [0, origin.width], [@min, @max] 414 | 415 | 416 | 417 | for component in components 418 | 419 | type = component.name.replace "_", "" 420 | 421 | do (component) -> 422 | 423 | component.addDesignChildren() 424 | 425 | if type == "SliderComponent" 426 | extendSlider component 427 | else if type == "RangeSliderComponent" 428 | extendRangeSlider component 429 | -------------------------------------------------------------------------------- /Demo.framer/modules/DesignComponents.coffee: -------------------------------------------------------------------------------- 1 | 2 | ### 3 | ------------------ 4 | CUSTOM CLASSES 5 | ------------------ 6 | ### 7 | 8 | kit = Layer.select "*UIKit*" 9 | if kit? then kit.x = Screen.width * 1000; kit.name = ".UIKit" 10 | 11 | for layer in Layer.selectAll "@*" 12 | parent = layer.parent 13 | name = layer.name.replace "@", "" 14 | parent[name] = layer 15 | 16 | customComponents = Layer.selectAll "Custom_*" 17 | 18 | Layer::addDesignChildren = (origin) -> 19 | if !origin? then origin = @ 20 | for child in origin.selectAllChildren ("*") 21 | parent = child.parent 22 | parent[child.name] = child 23 | 24 | 25 | stateChangeProps = [ 26 | "width", "height", 27 | "opacity", 28 | "scaleX", "scaleY", "scaleZ", "scale", 29 | "skewX", "skewY", "skew", 30 | "rotationX", "rotationY", "rotationZ", "rotation", 31 | "blur", 32 | "brightness", "saturate", "hueRotate", "contrast", "invert", "grayscale", "sepia", "blending", 33 | "backgroundBlur", "backgroundBrightness", "backgroundSaturate", "backgroundHueRotate", "backgroundContrast", "backgroundInvert", "backgroundGrayscale", "backgroundSepia", 34 | "shadow1", "shadow2", "shadow3", "shadow4", "shadow5", "shadow6", "shadow7", "shadow8", "shadow9", 35 | "shadowX", "shadowY", "shadowBlur", "shadowSpread", "shadowColor", "shadowType", 36 | "shadows", 37 | "backgroundColor", "color", 38 | "borderRadius", "borderColor", "borderWidth", "borderStyle", 39 | "image", "gradient", 40 | "text", 41 | "fill", "stroke", "strokeWidth", "strokeWidthMultiplier" 42 | ] 43 | 44 | 45 | pushParent = (layer, direction) -> 46 | layer.pushValues = 47 | marginBottom: layer.parent.height - layer.maxY 48 | marginRight: layer.parent.width - layer.maxX 49 | 50 | if direction == "down" 51 | layer.onChange "y", -> 52 | @parent.height = layer.maxY + @pushValues.marginBottom 53 | layer.onChange "height", -> 54 | @parent.height = layer.maxY + @pushValues.marginBottom 55 | 56 | buildConstraintsProtos = (constructorName) -> 57 | 58 | constructorName = eval constructorName 59 | 60 | constructorName::setConstraints = (options={}, origin) -> 61 | @constraintValues = 62 | top: if typeof options?.top == "object" then null else if options?.top? && typeof options.top == "number" then options.top else origin?.constraintValues?.top || null 63 | left: if typeof options?.left == "object" then null else if options?.left? && typeof options.top == "number" then options.top else origin?.constraintValues?.left || null 64 | bottom: if typeof options?.bottom == "object" then null else if options?.pushDown then null else if options?.bottom? && typeof options.bottom == "number" then options.bottom else origin?.constraintValues?.bottom || null 65 | right: if typeof options?.right == "object" then null else if options?.pushRight then null else if options?.right? && typeof options.right == "number" then options.right else origin?.constraintValues?.right || null 66 | width: @width 67 | height: @height 68 | widthFactor: options?.scaleX || options?.widthFactor || null 69 | heightFactor: options?.scaleY ||options?.heightFactor || null 70 | centerAnchorX: options?.centerX || options?.centerAnchorX || null 71 | centerAnchorY: options?.centerY || options?.centerAnchorY || null 72 | aspectRatioLocked: if options?.aspectRatioLocked? then options.aspectRatioLocked else if origin?.constraintValues?.aspectRatioLocked? then origin.constraintValues.aspectRatioLocked else false 73 | 74 | if options.pushDown? 75 | @constraintValues.bottom = null 76 | pushParent @, "down" 77 | if options.pushRight? 78 | @constraintValues.right = null 79 | pushParent @, "right" 80 | 81 | constraints = @constraintValues 82 | textLayerAutoSize = typeof @ == TextLayer && @autoSize 83 | 84 | @onChange "y", -> 85 | @constraintValues = constraints 86 | @onChange "x", -> 87 | @constraintValues = constraints 88 | @onChange "height", -> 89 | @constraintValues = constraints 90 | @onChange "width", -> 91 | @constraintValues = constraints 92 | 93 | @applyConstraints() 94 | 95 | constructorName::applyConstraints = -> 96 | 97 | return if !@constraintValues 98 | 99 | values = @constraintValues 100 | 101 | if !@parent then parent = Screen else parent = @parent 102 | 103 | aspectRatio = @width / @height 104 | 105 | # position 106 | if values.top? && typeof values.top != "object" 107 | @y = values.top 108 | else if values.top == null && values.topRef?.layer? 109 | @y = values.topRef.layer[values.topRef.align] + values.topRef.value 110 | 111 | if values.left? && typeof values.left != "object" 112 | @x = values.left 113 | else if values.left == null && values.leftRef?.layer? 114 | @x = values.leftRef.layer[values.leftRef.align] + values.leftRef.value 115 | 116 | # size 117 | if values.left? && values.right? 118 | @width = parent.width - @x - values.right 119 | if values.aspectRatioLocked 120 | @height = @width / aspectRatio 121 | if values.top? && values.bottom? 122 | @height = parent.height - @y - values.bottom 123 | if values.aspectRatioLocked 124 | @width = @height * aspectRatio 125 | 126 | if values.widthFactor? 127 | @width = parent.width * values.widthFactor 128 | if values.heightFactor? 129 | @height = parent.height * values.heightFactor 130 | 131 | # max position 132 | if values.right? 133 | @maxX = parent.width - values.right 134 | else if values.right == null && values.rightRef?.layer? 135 | @maxX = values.rightRef.layer[values.rightRef.align] - values.rightRef.value 136 | if values.bottom? 137 | @maxY = parent.height - values.bottom 138 | else if values.bottom == null && values.bottomRef?.layer? 139 | @maxY = values.bottomRef.layer[values.bottomRef.align] - values.bottomRef.value 140 | 141 | # center position 142 | if !values.left? && !values.right? && values.centerAnchorX? 143 | @midX = parent.width * values.centerAnchorX 144 | if !values.top? && !values.bottom? && values.centerAnchorY? 145 | @midY = parent.height * values.centerAnchorY 146 | 147 | @constraintValues = values 148 | 149 | 150 | layerTypes = ["Layer", "TextLayer", "ScrollComponent", "PageComponent", "SliderComponent", "RangeSliderComponent", "SVGLayer", "BackgroundLayer", "SVGPath", "SVGGroup"] 151 | for type in layerTypes 152 | buildConstraintsProtos(type) 153 | 154 | Object.defineProperty(Layer.prototype, "constraints", { 155 | get: -> return @constraintValues 156 | set: (value) -> 157 | @_constraints = value 158 | @emit "change:constraints", value 159 | @setConstraints value 160 | }) 161 | 162 | for component in customComponents 163 | name = component.name.replace "Custom_", "" 164 | 165 | do (component, name) -> 166 | class exports[name] extends Layer 167 | constructor: (@options={}) -> 168 | super @options 169 | @props = Object.assign component.props, {parent: @options.parent || null} 170 | 171 | if @options.constraints? 172 | @constraints = @options.constraints 173 | @props = @options 174 | 175 | @addChildren() 176 | @assignChildren() 177 | @setDescendantProps() 178 | @setDescendantConstraints() 179 | 180 | @stateComponents = Layer.selectAll "*State_#{name}*" 181 | @addStates() 182 | 183 | if @options.state? 184 | @animateState @options.state, false 185 | 186 | addChildren: -> 187 | newParent = component.copy() 188 | for child in newParent.children 189 | if child instanceof SVGPath or child instanceof SVGGroup 190 | Utils.throwInStudioOrWarnInProduction "SVG '#{child.name}' in 'Custom_#{name}' must be wrapped in a Frame in order to create a Design Component Symbol" 191 | else 192 | child.parent = @ 193 | if child instanceof TextLayer && component.selectChild(child.name)? 194 | child.autoSize = true 195 | newParent.destroy() 196 | 197 | assignChildren: -> 198 | for descendant in @descendants 199 | @[descendant.name] = descendant 200 | 201 | setDescendantProps: -> 202 | for descendant in @descendants 203 | do (descendant) => 204 | if @options[descendant.name] 205 | @[descendant.name].constraints = @options[descendant.name].constraints || undefined 206 | @[descendant.name].props = @options[descendant.name] 207 | 208 | setDescendantConstraints: -> 209 | for descendant in @descendants 210 | decName = descendant.name 211 | origin = component.selectChild decName 212 | descendant.setConstraints( 213 | @options[decName]?.constraints || {}, 214 | origin 215 | ) 216 | 217 | addStates: -> 218 | @customStates = 219 | array: [] 220 | 221 | for state in @stateComponents 222 | do (state) => 223 | stateIndex = state.name.indexOf "State" 224 | if stateIndex > 0 225 | stateName = state.name.slice 0, stateIndex-1 226 | else 227 | stateName = state.name.split("State_#{name}_")[1] 228 | 229 | @customStates[stateName] = {} 230 | @customStates.array.push stateName 231 | 232 | addProps = (layer, origin) -> 233 | stateProps = {} 234 | for prop in stateChangeProps 235 | stateProps[prop] = origin[prop] 236 | 237 | if origin instanceof SVGLayer 238 | split1 = origin['html'].split(/opacity/)[1] 239 | if (split1[0] != ':') 240 | split2 = split1.split(/"/)[1] 241 | stateProps['opacity'] = split2 242 | else 243 | stateProps['opacity'] = "1.0" 244 | 245 | layer.states[stateName] = stateProps 246 | 247 | addProps @, state 248 | 249 | for descendant in state.descendants 250 | do (descendant) => 251 | addProps @[descendant.name], descendant 252 | if descendant instanceof SVGPath 253 | addProps @[descendant.name].parent._children[0], descendant.parent._children[0] 254 | 255 | @addStateEvents() 256 | 257 | addStateEvents: -> 258 | events = [] 259 | 260 | for state in @stateComponents 261 | if state.name.includes "_State_#{name}" 262 | stateName = state.name.split("_State_#{name}")[0] 263 | eventName = state.name.split("_State_#{name}")[1] 264 | else 265 | eventName = state.name.replace "State_#{name}_", "" 266 | stateName = eventName 267 | 268 | if eventName.includes "_Animate" 269 | animate = true 270 | eventName = eventName.split("_Animate")[0] 271 | else animate = false 272 | 273 | eventName = eventName.replace "_", "" 274 | 275 | @customStates[stateName].animate = animate 276 | 277 | unless events.includes eventName then events.push eventName 278 | 279 | for eventName in events 280 | 281 | do (eventName) => 282 | 283 | if Events[eventName]? && @customStates.array.includes eventName 284 | 285 | @on Events[eventName], (event, layer) -> 286 | 287 | animateBool = @customStates[eventName].animate 288 | 289 | @stateSwitch(eventName, {animate: animateBool}) 290 | @animateChildren() 291 | 292 | else if Events[eventName]? 293 | 294 | @on Events[eventName], -> 295 | currentIndex = @customStates.array.indexOf(@states.current.name) 296 | nextIndex = currentIndex + 1 297 | if nextIndex == @customStates.array.length then nextIndex = 0 298 | animateBool = @customStates[@customStates.array[nextIndex]].animate 299 | nextState = @customStates.array[nextIndex] 300 | 301 | @stateSwitch(nextState, {animate: animateBool}) 302 | @animateChildren() 303 | 304 | animateChildren: (stateName, animate, options={}) -> 305 | unless stateName? then stateName = @states.current.name 306 | unless animate? then animate = @customStates[stateName].animate 307 | if !animate then options.time = 0 308 | for dec in @descendants 309 | do (dec) => 310 | if dec instanceof SVGPath 311 | # dec.stateSwitch(stateName, {animate: animate, options: options}) 312 | 313 | dec.parent._children[0].stateSwitch(stateName, {animate: animate, options: options}) 314 | else 315 | dec.stateSwitch(stateName, {animate: animate, options: options}) 316 | 317 | animateState: (state, animate, options={}) -> 318 | 319 | if !state? || !@customStates?[state]? then return 320 | if !animate? && @customStates?[state]? then animate = @customStates[state].animate else if animate? then animate = animate else animate = false 321 | if !animate then options.time = 0 322 | 323 | @stateSwitch(state, {animate: animate, options: options}) 324 | @animateChildren(state, animate, options) 325 | 326 | @define "state", 327 | get: -> @options.state 328 | set: (value) -> 329 | @options.state = value 330 | @emit("change:state", @options.state) 331 | @animateState value 332 | 333 | 334 | 335 | customStates = Layer.selectAll "State_*" 336 | 337 | for componentState in customStates 338 | 339 | classEventName = componentState.name.replace "State_", "" 340 | if classEventName.includes "_" 341 | className = classEventName.split("_")[0] 342 | eventName = classEventName.split("_")[1] 343 | else 344 | className = classEventName 345 | 346 | 347 | ### 348 | ------------------ 349 | EXISTING CLASSES 350 | ------------------ 351 | ### 352 | 353 | 354 | components = Layer.selectAll "_*" 355 | 356 | extendSlider = (origin) -> 357 | class exports.SliderComponent extends SliderComponent 358 | 359 | constructor: (@options={}) -> 360 | super @options 361 | 362 | @knob.props = 363 | shadows: origin.knob.shadows 364 | backgroundColor: origin.knob.backgroundColor 365 | borderRadius: origin.knob.borderRadius 366 | frame: origin.knob.frame 367 | 368 | @fill.props = 369 | shadows: origin.fill.shadows 370 | backgroundColor: origin.fill.backgroundColor 371 | borderRadius: origin.fill.borderRadius 372 | frame: origin.fill.frame 373 | 374 | @props = 375 | shadows: origin.shadows 376 | backgroundColor: origin.backgroundColor 377 | borderRadius: origin.borderRadius 378 | size: origin.size 379 | 380 | @value = Utils.modulate origin.knob.midX, [0, origin.width], [@min, @max] 381 | 382 | 383 | extendRangeSlider = (origin) -> 384 | class exports.RangeSliderComponent extends RangeSliderComponent 385 | 386 | constructor: (@options={}) -> 387 | super @options 388 | 389 | @minKnob.props = 390 | shadows: origin.minKnob.shadows 391 | backgroundColor: origin.minKnob.backgroundColor 392 | borderRadius: origin.minKnob.borderRadius 393 | frame: origin.minKnob.frame 394 | @maxKnob.props = 395 | shadows: origin.maxKnob.shadows 396 | backgroundColor: origin.maxKnob.backgroundColor 397 | borderRadius: origin.maxKnob.borderRadius 398 | frame: origin.maxKnob.frame 399 | 400 | @fill.props = 401 | shadows: origin.fill.shadows 402 | backgroundColor: origin.fill.backgroundColor 403 | borderRadius: origin.fill.borderRadius 404 | frame: origin.fill.frame 405 | 406 | @props = 407 | shadows: origin.shadows 408 | backgroundColor: origin.backgroundColor 409 | borderRadius: origin.borderRadius 410 | size: origin.size 411 | 412 | @minValue = Utils.modulate origin.minKnob.midX, [0, origin.width], [@min, @max] 413 | @maxValue = Utils.modulate origin.maxKnob.midX, [0, origin.width], [@min, @max] 414 | 415 | 416 | 417 | for component in components 418 | 419 | type = component.name.replace "_", "" 420 | 421 | do (component) -> 422 | 423 | component.addDesignChildren() 424 | 425 | if type == "SliderComponent" 426 | extendSlider component 427 | else if type == "RangeSliderComponent" 428 | extendRangeSlider component 429 | -------------------------------------------------------------------------------- /Demo.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {var __layer_0__ = new Layer({"name":".UIKit","backgroundColor":"hsl(0, 0%, 81%)","width":375,"x":717,"height":1408,"constraintValues":null,"blending":"normal","clip":true,"borderStyle":"solid"});var Custom_Card = new Layer({"parent":__layer_0__,"name":"Custom_Card","shadows":[{"spread":0,"x":0,"type":"box","y":4,"blur":6,"color":"rgba(0, 0, 0, 0.15)"}],"backgroundColor":"rgb(252, 252, 252)","width":355,"x":10,"height":117,"constraintValues":{"left":10,"height":117,"centerAnchorX":0.5,"width":355,"right":10,"top":13,"centerAnchorY":0.1071964017991004},"blending":"normal","borderRadius":5,"clip":false,"borderStyle":"solid","y":13});var __layer_1__ = new Layer({"parent":Custom_Card,"name":"arrow","backgroundColor":null,"width":11,"x":323,"height":21,"constraintValues":{"left":null,"height":21,"centerAnchorX":0.9253521126760563,"width":11,"bottom":17,"right":21,"top":null,"centerAnchorY":0.7649572649572649},"blending":"normal","clip":false,"borderStyle":"solid","y":79});var __layer_2__ = new SVGLayer({"parent":__layer_1__,"name":".SVGLayer","backgroundColor":null,"width":10.5,"stroke":"#AAA","strokeWidth":2,"htmlIntrinsicSize":{"height":21,"width":10.5},"rotation":null,"height":21,"opacity":null,"y":-0.5,"svg":"<\/path><\/svg>"});var __layer_3__ = new TextLayer({"parent":Custom_Card,"name":"content","backgroundColor":null,"width":295,"x":30,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":7,"css":{"fontSize":"14px","WebkitTextFillColor":"hsl(231, 41%, 19%)","letterSpacing":"0px","lineHeight":"1.2","fontWeight":200,"tabSize":4,"fontFamily":"\"AktivGrotesk-Light\", \"Aktiv Grotesk\", serif"}}],"text":"Content"}]},"height":16,"constraintValues":{"left":30,"height":16,"centerAnchorX":0.5,"width":295,"right":30,"top":81,"centerAnchorY":0.7606837606837606},"blending":"normal","autoSize":false,"y":81});var __layer_4__ = new TextLayer({"parent":Custom_Card,"name":"subheader","backgroundColor":null,"width":295,"x":30,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":10,"css":{"fontSize":"18px","WebkitTextFillColor":"rgb(34, 34, 34)","letterSpacing":"0px","lineHeight":"1.2","fontWeight":500,"tabSize":4,"fontFamily":"\"AktivGrotesk-Medium\", \"Aktiv Grotesk\", serif"}}],"text":"Subheading"}]},"height":21,"constraintValues":{"left":30,"height":21,"centerAnchorX":0.5,"width":295,"right":30,"top":54,"centerAnchorY":0.5512820512820513},"blending":"normal","autoSize":false,"y":54});var __layer_5__ = new TextLayer({"parent":Custom_Card,"name":"title","backgroundColor":null,"width":295,"x":30,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":5,"css":{"fontSize":"24px","WebkitTextFillColor":"hsl(229, 28%, 15%)","letterSpacing":"0px","lineHeight":"1.2","fontWeight":200,"tabSize":4,"fontFamily":"\"AktivGrotesk-Light\", \"Aktiv Grotesk\", serif"}}],"text":"Title"}]},"height":28,"constraintValues":{"left":30,"height":28,"centerAnchorX":0.5,"width":295,"right":30,"top":20,"centerAnchorY":0.2905982905982906},"blending":"normal","autoSize":false,"y":20});var __layer_6__ = new Layer({"parent":Custom_Card,"name":"avatar","backgroundColor":"rgba(0,170,255,0.5)","width":33,"x":312,"height":33,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":33,"centerAnchorX":0.9253521126760563,"width":33,"bottom":74,"right":10,"top":10,"centerAnchorY":0.2264957264957265},"blending":"normal","borderRadius":20,"clip":false,"borderStyle":"solid","y":10});var __layer_7__ = new Layer({"parent":__layer_0__,"name":"State_Button_MouseUp","backgroundColor":null,"width":243,"x":66,"height":56,"constraintValues":{"left":null,"height":56,"centerAnchorX":0.5,"width":243,"top":307,"centerAnchorY":0.2379261363636364},"blending":"normal","clip":false,"borderStyle":"solid","y":307});var __layer_8__ = new Layer({"parent":__layer_7__,"name":"rectangle","shadows":[{"spread":0,"x":0,"type":"box","y":2,"blur":5,"color":"rgba(0,0,0,0.25)"}],"borderWidth":1,"backgroundColor":null,"width":243,"borderColor":"rgb(0, 0, 0)","height":55,"constraintValues":{"height":55,"centerAnchorX":0.5,"width":243,"bottom":1,"right":0,"centerAnchorY":0.4910714285714285},"blending":"normal","clip":false,"borderStyle":"solid"});var __layer_9__ = new TextLayer({"parent":__layer_8__,"name":"text","backgroundColor":null,"width":71,"x":87,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":9,"css":{"fontSize":"16px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"Click me!"}],"alignment":"center"},"height":20,"constraintValues":{"left":null,"height":20,"centerAnchorX":0.5041152263374485,"width":71,"top":null,"centerAnchorY":0.509090909090909},"blending":"normal","autoSize":true,"y":18});var __layer_10__ = new Layer({"parent":__layer_0__,"name":"State_Button_MouseDown","backgroundColor":null,"width":243,"x":66,"height":56,"constraintValues":{"left":null,"height":56,"centerAnchorX":0.5,"width":243,"top":245,"centerAnchorY":0.1938920454545454},"blending":"normal","clip":false,"borderStyle":"solid","y":245});var __layer_11__ = new Layer({"parent":__layer_10__,"name":"rectangle","shadows":[{"spread":0,"x":0,"type":"box","y":0,"blur":5,"color":"rgba(0,0,0,0.25)"}],"borderWidth":1,"backgroundColor":"hsla(0, 0%, 0%, 0.79)","width":243,"borderColor":"rgb(0, 0, 0)","height":55,"constraintValues":{"height":55,"centerAnchorX":0.5,"width":243,"bottom":0,"right":0,"top":1,"centerAnchorY":0.5089285714285714},"blending":"normal","clip":false,"borderStyle":"solid","y":1});var __layer_12__ = new TextLayer({"parent":__layer_11__,"name":"text","backgroundColor":null,"width":71,"x":87,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":9,"css":{"fontSize":"16px","WebkitTextFillColor":"hsl(0, 0%, 100%)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"Click me!"}],"alignment":"center"},"height":20,"constraintValues":{"left":null,"height":20,"centerAnchorX":0.5041152263374485,"width":71,"top":null,"centerAnchorY":0.509090909090909},"blending":"normal","autoSize":true,"y":18});var __layer_13__ = new Layer({"parent":__layer_0__,"name":"Custom_Button","backgroundColor":null,"width":243,"x":66,"height":56,"constraintValues":{"left":null,"height":56,"centerAnchorX":0.5,"width":243,"top":170,"centerAnchorY":0.2071129707112971},"blending":"normal","clip":false,"borderStyle":"solid","y":170});var __layer_14__ = new Layer({"parent":__layer_13__,"name":"rectangle","shadows":[{"spread":0,"x":0,"type":"box","y":2,"blur":5,"color":"rgba(0,0,0,0.25)"}],"borderWidth":1,"backgroundColor":null,"width":243,"borderColor":"rgb(0, 0, 0)","height":55,"constraintValues":{"height":55,"centerAnchorX":0.5,"width":243,"bottom":1,"right":0,"centerAnchorY":0.4910714285714285},"blending":"normal","clip":false,"borderStyle":"solid"});var __layer_15__ = new TextLayer({"parent":__layer_14__,"name":"text","backgroundColor":null,"width":71,"x":87,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":9,"css":{"fontSize":"16px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"Click me!"}],"alignment":"center"},"height":20,"constraintValues":{"left":null,"height":20,"centerAnchorX":0.5041152263374485,"width":71,"top":null,"centerAnchorY":0.509090909090909},"blending":"normal","autoSize":true,"y":18});var __layer_16__ = new Layer({"parent":__layer_0__,"name":"Success_State_Toggle_Tap_Animate","borderWidth":1,"backgroundColor":"hsla(139, 100%, 71%, 0.5)","width":125,"x":20,"borderColor":"#222","height":125,"constraintValues":{"left":20,"aspectRatioLocked":true,"height":125,"centerAnchorX":0.22,"width":125,"top":522,"centerAnchorY":0.6114016736401674},"blending":"normal","borderRadius":15,"clip":false,"borderStyle":"solid","y":522});var __layer_17__ = new Layer({"parent":__layer_0__,"name":"Warning_State_Toggle_Tap","borderWidth":1,"backgroundColor":"hsla(54, 100%, 71%, 0.5)","width":125,"x":178,"borderColor":"#222","height":125,"constraintValues":{"left":178,"aspectRatioLocked":true,"height":125,"centerAnchorX":0.6413333333333333,"width":125,"top":522,"centerAnchorY":0.6114016736401674},"blending":"normal","borderRadius":30,"clip":false,"borderStyle":"solid","y":522});var __layer_18__ = new Layer({"parent":__layer_0__,"name":"Error_State_Toggle_Tap_Animate","borderWidth":1,"backgroundColor":"hsla(0, 100%, 71%, 0.5)","width":125,"x":20,"borderColor":"#222","height":125,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":125,"centerAnchorX":0.22,"width":125,"right":230,"top":662,"centerAnchorY":0.7578451882845189},"blending":"normal","borderRadius":60,"opacity":0.6,"clip":false,"borderStyle":"solid","y":662});var __layer_19__ = new Layer({"parent":__layer_0__,"name":"Default_State_Toggle_Tap","borderWidth":1,"backgroundColor":"hsla(0, 0%, 100%, 0.5)","width":125,"x":178,"borderColor":"#222","height":125,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":125,"centerAnchorX":0.6413333333333333,"width":125,"right":72,"top":662,"centerAnchorY":0.7578451882845189},"blending":"normal","clip":false,"borderStyle":"solid","y":662});var __layer_20__ = new Layer({"parent":__layer_0__,"name":"Custom_Toggle","borderWidth":1,"backgroundColor":"hsla(0, 0%, 100%, 0.5)","width":125,"x":20,"borderColor":"#222","height":125,"constraintValues":{"left":20,"aspectRatioLocked":true,"height":125,"centerAnchorX":0.1533333333333333,"width":125,"top":380,"centerAnchorY":0.6259370314842578},"blending":"normal","clip":false,"borderStyle":"solid","y":380});var __layer_21__ = new Layer({"parent":__layer_0__,"name":"_RangeSliderComponent","backgroundColor":"rgba(0,170,255,0.5)","width":295,"x":40,"height":10,"constraintValues":{"left":40,"height":10,"centerAnchorX":0.5,"width":295,"top":892,"centerAnchorY":0.9382845188284519},"blending":"normal","clip":false,"borderStyle":"solid","y":892});var __layer_22__ = new Layer({"parent":__layer_21__,"name":"fill","backgroundColor":"hsla(124, 100%, 50%, 0.5)","width":154,"x":81,"height":10,"constraintValues":{"left":null,"height":10,"centerAnchorX":0.535593220338983,"width":154,"bottom":0,"right":60,"centerAnchorY":0.5},"blending":"normal","clip":false,"borderStyle":"solid"});var __layer_23__ = new Layer({"parent":__layer_21__,"name":"maxKnob","shadows":[{"spread":0,"x":2,"type":"box","y":2,"blur":0,"color":"hsl(0, 0%, 0%)"}],"backgroundColor":"#E48B8B","width":30,"x":220,"height":30,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":30,"centerAnchorX":0.7966101694915254,"width":30,"bottom":-10,"right":45,"top":-10,"centerAnchorY":0.5},"blending":"normal","clip":false,"borderStyle":"solid","y":-10});var __layer_24__ = new Layer({"parent":__layer_21__,"name":"minKnob","shadows":[{"spread":0,"x":2,"type":"box","y":2,"blur":0,"color":"hsl(0, 0%, 0%)"}],"backgroundColor":"#E48B8B","width":30,"x":66,"height":30,"constraintValues":{"left":66,"aspectRatioLocked":true,"height":30,"centerAnchorX":0.2745762711864407,"width":30,"bottom":-10,"top":-10,"centerAnchorY":0.5},"blending":"normal","clip":false,"borderStyle":"solid","y":-10});var __layer_25__ = new Layer({"parent":__layer_0__,"name":"_SliderComponent","backgroundColor":"rgba(0,170,255,0.5)","width":295,"x":40,"height":10,"constraintValues":{"left":40,"height":10,"centerAnchorX":0.5,"width":295,"top":848,"centerAnchorY":0.8922594142259415},"blending":"normal","clip":false,"borderStyle":"solid","y":848});var __layer_26__ = new Layer({"parent":__layer_25__,"name":"fill","backgroundColor":"hsla(124, 100%, 50%, 0.5)","width":148,"height":10,"constraintValues":{"height":10,"centerAnchorX":0.2508474576271186,"width":148,"bottom":0,"centerAnchorY":0.5},"blending":"normal","clip":false,"borderStyle":"solid"});var __layer_27__ = new Layer({"parent":__layer_25__,"name":"knob","shadows":[{"spread":0,"x":2,"type":"box","y":2,"blur":0,"color":"hsl(0, 0%, 0%)"}],"backgroundColor":"hsl(0, 62%, 72%)","width":30,"x":133,"height":30,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":30,"centerAnchorX":0.5016949152542373,"width":30,"bottom":-10,"top":-10,"centerAnchorY":0.5},"blending":"normal","clip":false,"borderStyle":"solid","y":-10});var __layer_28__ = new TextLayer({"parent":__layer_0__,"backgroundColor":null,"width":85,"x":121,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":8,"css":{"fontSize":"16px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😀😇😜😒"}]},"height":19,"constraintValues":{"left":121,"height":19,"centerAnchorX":0.352,"width":85,"bottom":439,"top":950,"centerAnchorY":0.6814630681818182},"blending":"normal","autoSize":true,"y":950});var __layer_29__ = new Layer({"parent":__layer_0__,"backgroundBlur":10,"name":"Custom_Emoji","backgroundColor":"rgba(0,170,255,0.5)","width":101,"x":25,"height":101,"constraintValues":{"left":25,"aspectRatioLocked":true,"height":101,"centerAnchorX":0.2013333333333333,"width":101,"bottom":328,"top":null,"centerAnchorY":0.7311789772727273},"blending":"normal","borderRadius":"50%","clip":false,"borderStyle":"solid","y":979});var __layer_30__ = new TextLayer({"parent":__layer_29__,"backgroundColor":null,"width":33,"x":34,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":2,"css":{"fontSize":"32px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😀"}],"alignment":"center"},"height":38,"constraintValues":{"left":null,"height":38,"centerAnchorX":0.5,"width":33,"top":null,"centerAnchorY":0.5247524752475248},"blending":"normal","autoSize":true,"y":34});var __layer_31__ = new Layer({"parent":__layer_0__,"backgroundBlur":10,"name":"Angel_State_Emoji","backgroundColor":"hsla(260, 100%, 50%, 0.5)","width":101,"x":191,"height":101,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":101,"centerAnchorX":0.644,"width":101,"bottom":212,"right":83,"top":null,"centerAnchorY":0.8135653409090909},"blending":"normal","borderRadius":"50%","clip":false,"borderStyle":"solid","y":1095});var __layer_32__ = new TextLayer({"parent":__layer_31__,"backgroundColor":null,"width":33,"x":34,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":2,"css":{"fontSize":"32px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😇"}],"alignment":"center"},"height":38,"constraintValues":{"left":null,"height":38,"centerAnchorX":0.5,"width":33,"top":null,"centerAnchorY":0.5247524752475248},"blending":"normal","autoSize":true,"y":34});var __layer_33__ = new Layer({"parent":__layer_0__,"backgroundBlur":10,"name":"Smile_State_Emoji","backgroundColor":"rgba(0,170,255,0.5)","width":101,"x":25,"height":101,"constraintValues":{"left":25,"aspectRatioLocked":true,"height":101,"centerAnchorX":0.2013333333333333,"width":101,"bottom":212,"top":null,"centerAnchorY":0.8135653409090909},"blending":"normal","borderRadius":"50%","clip":false,"borderStyle":"solid","y":1095});var __layer_34__ = new TextLayer({"parent":__layer_33__,"backgroundColor":null,"width":33,"x":34,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":2,"css":{"fontSize":"32px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😀"}],"alignment":"center"},"height":38,"constraintValues":{"left":null,"height":38,"centerAnchorX":0.5,"width":33,"top":null,"centerAnchorY":0.5247524752475248},"blending":"normal","autoSize":true,"y":34});var __layer_35__ = new Layer({"parent":__layer_0__,"backgroundBlur":10,"name":"Unamused_State_Emoji","backgroundColor":"hsla(41, 100%, 50%, 0.5)","width":101,"x":191,"height":101,"constraintValues":{"left":null,"aspectRatioLocked":true,"height":101,"centerAnchorX":0.644,"width":101,"bottom":96,"right":83,"top":null,"centerAnchorY":0.8959517045454546},"blending":"normal","borderRadius":"50%","clip":false,"borderStyle":"solid","y":1211});var __layer_36__ = new TextLayer({"parent":__layer_35__,"backgroundColor":null,"width":33,"x":34,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":2,"css":{"fontSize":"32px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😒"}],"alignment":"center"},"height":38,"constraintValues":{"left":null,"height":38,"centerAnchorX":0.5,"width":33,"top":null,"centerAnchorY":0.5247524752475248},"blending":"normal","autoSize":true,"y":34});var __layer_37__ = new Layer({"parent":__layer_0__,"backgroundBlur":10,"name":"Wink_State_Emoji","backgroundColor":"hsla(156, 100%, 50%, 0.5)","width":101,"x":25,"height":101,"constraintValues":{"left":25,"aspectRatioLocked":true,"height":101,"centerAnchorX":0.2013333333333333,"width":101,"bottom":96,"top":null,"centerAnchorY":0.8959517045454546},"blending":"normal","borderRadius":"50%","clip":false,"borderStyle":"solid","y":1211});var __layer_38__ = new TextLayer({"parent":__layer_37__,"backgroundColor":null,"width":33,"x":34,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":2,"css":{"fontSize":"32px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","letterSpacing":"0px","lineHeight":"1.2","tabSize":4,"fontFamily":"\".SFNSText\", \"SFProText-Regular\", \"SFUIText-Regular\", \".SFUIText\", sans-serif"}}],"text":"😜"}],"alignment":"center"},"height":38,"constraintValues":{"left":null,"height":38,"centerAnchorX":0.5,"width":33,"top":null,"centerAnchorY":0.5247524752475248},"blending":"normal","autoSize":true,"y":34});var __layer_39__ = new Layer({"backgroundColor":"hsl(255, 67%, 65%)","width":178,"x":324,"height":184,"constraintValues":null,"blending":"normal","clip":false,"borderStyle":"solid","y":90});if(__layer_30__ !== undefined){__layer_30__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_30__","vekterClass":"TextNode","text":"😀"}};if(__layer_9__ !== undefined){__layer_9__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_9__","vekterClass":"TextNode","text":"Click me!"}};if(__layer_25__ !== undefined){__layer_25__.__framerInstanceInfo = {"hash":"#vekter|__layer_25__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_36__ !== undefined){__layer_36__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_36__","vekterClass":"TextNode","text":"😒"}};if(__layer_10__ !== undefined){__layer_10__.__framerInstanceInfo = {"hash":"#vekter|__layer_10__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_32__ !== undefined){__layer_32__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_32__","vekterClass":"TextNode","text":"😇"}};if(__layer_35__ !== undefined){__layer_35__.__framerInstanceInfo = {"hash":"#vekter|__layer_35__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_0__ !== undefined){__layer_0__.__framerInstanceInfo = {"hash":"#vekter|__layer_0__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_12__ !== undefined){__layer_12__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_12__","vekterClass":"TextNode","text":"Click me!"}};if(__layer_21__ !== undefined){__layer_21__.__framerInstanceInfo = {"hash":"#vekter|__layer_21__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_23__ !== undefined){__layer_23__.__framerInstanceInfo = {"hash":"#vekter|__layer_23__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_4__ !== undefined){__layer_4__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_4__","vekterClass":"TextNode","text":"Subheading"}};if(__layer_31__ !== undefined){__layer_31__.__framerInstanceInfo = {"hash":"#vekter|__layer_31__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_37__ !== undefined){__layer_37__.__framerInstanceInfo = {"hash":"#vekter|__layer_37__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_26__ !== undefined){__layer_26__.__framerInstanceInfo = {"hash":"#vekter|__layer_26__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_20__ !== undefined){__layer_20__.__framerInstanceInfo = {"hash":"#vekter|__layer_20__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_18__ !== undefined){__layer_18__.__framerInstanceInfo = {"hash":"#vekter|__layer_18__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_7__ !== undefined){__layer_7__.__framerInstanceInfo = {"hash":"#vekter|__layer_7__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_27__ !== undefined){__layer_27__.__framerInstanceInfo = {"hash":"#vekter|__layer_27__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_29__ !== undefined){__layer_29__.__framerInstanceInfo = {"hash":"#vekter|__layer_29__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_2__ !== undefined){__layer_2__.__framerInstanceInfo = {"hash":"#vekter|__layer_2__","vekterClass":"PathNode","framerClass":"SVGLayer"}};if(__layer_8__ !== undefined){__layer_8__.__framerInstanceInfo = {"hash":"#vekter|__layer_8__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_14__ !== undefined){__layer_14__.__framerInstanceInfo = {"hash":"#vekter|__layer_14__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_15__ !== undefined){__layer_15__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_15__","vekterClass":"TextNode","text":"Click me!"}};if(__layer_19__ !== undefined){__layer_19__.__framerInstanceInfo = {"hash":"#vekter|__layer_19__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_13__ !== undefined){__layer_13__.__framerInstanceInfo = {"hash":"#vekter|__layer_13__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_11__ !== undefined){__layer_11__.__framerInstanceInfo = {"hash":"#vekter|__layer_11__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_24__ !== undefined){__layer_24__.__framerInstanceInfo = {"hash":"#vekter|__layer_24__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_33__ !== undefined){__layer_33__.__framerInstanceInfo = {"hash":"#vekter|__layer_33__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_38__ !== undefined){__layer_38__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_38__","vekterClass":"TextNode","text":"😜"}};if(__layer_16__ !== undefined){__layer_16__.__framerInstanceInfo = {"hash":"#vekter|__layer_16__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_34__ !== undefined){__layer_34__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_34__","vekterClass":"TextNode","text":"😀"}};if(__layer_39__ !== undefined){__layer_39__.__framerInstanceInfo = {"hash":"#vekter|__layer_39__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_1__ !== undefined){__layer_1__.__framerInstanceInfo = {"hash":"#vekter|__layer_1__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_6__ !== undefined){__layer_6__.__framerInstanceInfo = {"hash":"#vekter|__layer_6__","vekterClass":"FrameNode","framerClass":"Layer"}};if(Custom_Card !== undefined){Custom_Card.__framerInstanceInfo = {"framerClass":"Layer","hash":"#vekter|Custom_Card","targetName":"Custom_Card","vekterClass":"FrameNode"}};if(__layer_17__ !== undefined){__layer_17__.__framerInstanceInfo = {"hash":"#vekter|__layer_17__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_22__ !== undefined){__layer_22__.__framerInstanceInfo = {"hash":"#vekter|__layer_22__","vekterClass":"FrameNode","framerClass":"Layer"}};if(__layer_3__ !== undefined){__layer_3__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_3__","vekterClass":"TextNode","text":"Content"}};if(__layer_28__ !== undefined){__layer_28__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_28__","vekterClass":"TextNode","text":"😀😇😜😒"}};if(__layer_5__ !== undefined){__layer_5__.__framerInstanceInfo = {"framerClass":"TextLayer","hash":"#vekter|__layer_5__","vekterClass":"TextNode","text":"Title"}};if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {Custom_Card});scope["__vekterVariables"] = ["Custom_Card"];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Demo.framer/framer/framer.modules.js: -------------------------------------------------------------------------------- 1 | require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { 563 | stateName = state.name.slice(0, stateIndex - 1); 564 | } else { 565 | stateName = state.name.split("State_" + name + "_")[1]; 566 | } 567 | _this.customStates[stateName] = {}; 568 | _this.customStates.array.push(stateName); 569 | addProps = function(layer, origin) { 570 | var len4, m, prop, stateProps; 571 | stateProps = {}; 572 | for (m = 0, len4 = stateChangeProps.length; m < len4; m++) { 573 | prop = stateChangeProps[m]; 574 | stateProps[prop] = origin[prop]; 575 | } 576 | return layer.states[stateName] = stateProps; 577 | }; 578 | addProps(_this, state); 579 | ref2 = state.descendants; 580 | results = []; 581 | for (m = 0, len4 = ref2.length; m < len4; m++) { 582 | descendant = ref2[m]; 583 | results.push((function(descendant) { 584 | return addProps(_this[descendant.name], descendant); 585 | })(descendant)); 586 | } 587 | return results; 588 | }; 589 | })(this); 590 | for (l = 0, len3 = ref1.length; l < len3; l++) { 591 | state = ref1[l]; 592 | fn1(state); 593 | } 594 | return this.addStateEvents(); 595 | }; 596 | 597 | _Class.prototype.addStateEvents = function() { 598 | var animate, eventName, events, l, len3, len4, m, ref1, results, state, stateName; 599 | events = []; 600 | ref1 = this.stateComponents; 601 | for (l = 0, len3 = ref1.length; l < len3; l++) { 602 | state = ref1[l]; 603 | if (state.name.includes("_State_" + name)) { 604 | stateName = state.name.split("_State_" + name)[0]; 605 | eventName = state.name.split("_State_" + name)[1]; 606 | } else { 607 | eventName = state.name.replace("State_" + name + "_", ""); 608 | stateName = eventName; 609 | } 610 | if (eventName.includes("_Animate")) { 611 | animate = true; 612 | eventName = eventName.split("_Animate")[0]; 613 | } else { 614 | animate = false; 615 | } 616 | eventName = eventName.replace("_", ""); 617 | this.customStates[stateName].animate = animate; 618 | if (!events.includes(eventName)) { 619 | events.push(eventName); 620 | } 621 | } 622 | results = []; 623 | for (m = 0, len4 = events.length; m < len4; m++) { 624 | eventName = events[m]; 625 | results.push((function(_this) { 626 | return function(eventName) { 627 | if ((Events[eventName] != null) && _this.customStates.array.includes(eventName)) { 628 | return _this.on(Events[eventName], function(event, layer) { 629 | var animateBool; 630 | animateBool = this.customStates[eventName].animate; 631 | this.stateSwitch(eventName, { 632 | animate: animateBool 633 | }); 634 | return this.animateChildren(); 635 | }); 636 | } else if (Events[eventName] != null) { 637 | return _this.on(Events[eventName], function() { 638 | var animateBool, currentIndex, nextIndex, nextState; 639 | currentIndex = this.customStates.array.indexOf(this.states.current.name); 640 | nextIndex = currentIndex + 1; 641 | if (nextIndex === this.customStates.array.length) { 642 | nextIndex = 0; 643 | } 644 | animateBool = this.customStates[this.customStates.array[nextIndex]].animate; 645 | nextState = this.customStates.array[nextIndex]; 646 | this.stateSwitch(nextState, { 647 | animate: animateBool 648 | }); 649 | return this.animateChildren(); 650 | }); 651 | } 652 | }; 653 | })(this)(eventName)); 654 | } 655 | return results; 656 | }; 657 | 658 | _Class.prototype.animateChildren = function(stateName, animate, options) { 659 | var dec, l, len3, ref1, results; 660 | if (options == null) { 661 | options = {}; 662 | } 663 | if (stateName == null) { 664 | stateName = this.states.current.name; 665 | } 666 | if (animate == null) { 667 | animate = this.customStates[stateName].animate; 668 | } 669 | if (!animate) { 670 | options.time = 0; 671 | } 672 | ref1 = this.descendants; 673 | results = []; 674 | for (l = 0, len3 = ref1.length; l < len3; l++) { 675 | dec = ref1[l]; 676 | results.push((function(_this) { 677 | return function(dec) { 678 | return dec.stateSwitch(stateName, { 679 | animate: animate, 680 | options: options 681 | }); 682 | }; 683 | })(this)(dec)); 684 | } 685 | return results; 686 | }; 687 | 688 | _Class.prototype.animateState = function(state, animate, options) { 689 | var ref1, ref2; 690 | if (options == null) { 691 | options = {}; 692 | } 693 | if ((state == null) || (((ref1 = this.customStates) != null ? ref1[state] : void 0) == null)) { 694 | return; 695 | } 696 | if ((animate == null) && (((ref2 = this.customStates) != null ? ref2[state] : void 0) != null)) { 697 | animate = this.customStates[state].animate; 698 | } else if (animate != null) { 699 | animate = animate; 700 | } else { 701 | animate = false; 702 | } 703 | if (!animate) { 704 | options.time = 0; 705 | } 706 | this.stateSwitch(state, { 707 | animate: animate, 708 | options: options 709 | }); 710 | return this.animateChildren(state, animate, options); 711 | }; 712 | 713 | _Class.define("state", { 714 | get: function() { 715 | return this.options.state; 716 | }, 717 | set: function(value) { 718 | this.options.state = value; 719 | this.emit("change:state", this.options.state); 720 | return this.animateState(value); 721 | } 722 | }); 723 | 724 | return _Class; 725 | 726 | })(Layer); 727 | }; 728 | for (k = 0, len2 = customComponents.length; k < len2; k++) { 729 | component = customComponents[k]; 730 | name = component.name.replace("Custom_", ""); 731 | fn(component, name); 732 | } 733 | 734 | customStates = Layer.selectAll("State_*"); 735 | 736 | for (l = 0, len3 = customStates.length; l < len3; l++) { 737 | componentState = customStates[l]; 738 | classEventName = componentState.name.replace("State_", ""); 739 | if (classEventName.includes("_")) { 740 | className = classEventName.split("_")[0]; 741 | eventName = classEventName.split("_")[1]; 742 | } else { 743 | className = classEventName; 744 | } 745 | } 746 | 747 | 748 | /* 749 | ------------------ 750 | EXISTING CLASSES 751 | ------------------ 752 | */ 753 | 754 | components = Layer.selectAll("_*"); 755 | 756 | extendSlider = function(origin) { 757 | return exports.SliderComponent = (function(superClass) { 758 | extend(SliderComponent, superClass); 759 | 760 | function SliderComponent(options1) { 761 | this.options = options1 != null ? options1 : {}; 762 | SliderComponent.__super__.constructor.call(this, this.options); 763 | this.knob.props = { 764 | shadows: origin.knob.shadows, 765 | backgroundColor: origin.knob.backgroundColor, 766 | borderRadius: origin.knob.borderRadius, 767 | frame: origin.knob.frame 768 | }; 769 | this.fill.props = { 770 | shadows: origin.fill.shadows, 771 | backgroundColor: origin.fill.backgroundColor, 772 | borderRadius: origin.fill.borderRadius, 773 | frame: origin.fill.frame 774 | }; 775 | this.props = { 776 | shadows: origin.shadows, 777 | backgroundColor: origin.backgroundColor, 778 | borderRadius: origin.borderRadius, 779 | size: origin.size 780 | }; 781 | this.value = Utils.modulate(origin.knob.midX, [0, origin.width], [this.min, this.max]); 782 | } 783 | 784 | return SliderComponent; 785 | 786 | })(SliderComponent); 787 | }; 788 | 789 | extendRangeSlider = function(origin) { 790 | return exports.RangeSliderComponent = (function(superClass) { 791 | extend(RangeSliderComponent, superClass); 792 | 793 | function RangeSliderComponent(options1) { 794 | this.options = options1 != null ? options1 : {}; 795 | RangeSliderComponent.__super__.constructor.call(this, this.options); 796 | this.minKnob.props = { 797 | shadows: origin.minKnob.shadows, 798 | backgroundColor: origin.minKnob.backgroundColor, 799 | borderRadius: origin.minKnob.borderRadius, 800 | frame: origin.minKnob.frame 801 | }; 802 | this.maxKnob.props = { 803 | shadows: origin.maxKnob.shadows, 804 | backgroundColor: origin.maxKnob.backgroundColor, 805 | borderRadius: origin.maxKnob.borderRadius, 806 | frame: origin.maxKnob.frame 807 | }; 808 | this.fill.props = { 809 | shadows: origin.fill.shadows, 810 | backgroundColor: origin.fill.backgroundColor, 811 | borderRadius: origin.fill.borderRadius, 812 | frame: origin.fill.frame 813 | }; 814 | this.props = { 815 | shadows: origin.shadows, 816 | backgroundColor: origin.backgroundColor, 817 | borderRadius: origin.borderRadius, 818 | size: origin.size 819 | }; 820 | this.minValue = Utils.modulate(origin.minKnob.midX, [0, origin.width], [this.min, this.max]); 821 | this.maxValue = Utils.modulate(origin.maxKnob.midX, [0, origin.width], [this.min, this.max]); 822 | } 823 | 824 | return RangeSliderComponent; 825 | 826 | })(RangeSliderComponent); 827 | }; 828 | 829 | fn1 = function(component) { 830 | component.addDesignChildren(); 831 | if (type === "SliderComponent") { 832 | return extendSlider(component); 833 | } else if (type === "RangeSliderComponent") { 834 | return extendRangeSlider(component); 835 | } 836 | }; 837 | for (m = 0, len4 = components.length; m < len4; m++) { 838 | component = components[m]; 839 | type = component.name.replace("_", ""); 840 | fn1(component); 841 | } 842 | 843 | 844 | },{}]},{},[]) 845 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWVyLm1vZHVsZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL1VzZXJzL3NlYmFzdGlhbi9Eb2N1bWVudHMvUm9ndWUgT25lL0dpdEh1Yi9mcmFtZXItRGVzaWduQ29tcG9uZW50cy9EZW1vLmZyYW1lci9tb2R1bGVzL0Rlc2lnbkNvbXBvbmVudHMuY29mZmVlIiwiLi4vLi4vLi4vLi4vLi4vVXNlcnMvc2ViYXN0aWFuL0RvY3VtZW50cy9Sb2d1ZSBPbmUvR2l0SHViL2ZyYW1lci1EZXNpZ25Db21wb25lbnRzL0RlbW8uZnJhbWVyL21vZHVsZXMvQ29uc3RyYWludHMuY29mZmVlIiwibm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbiMjI1xuLS0tLS0tLS0tLS0tLS0tLS0tXG5DVVNUT00gQ0xBU1NFU1xuLS0tLS0tLS0tLS0tLS0tLS0tXG4jIyNcblxua2l0ID0gTGF5ZXIuc2VsZWN0IFwiKlVJS2l0KlwiXG5pZiBraXQ/IHRoZW4ga2l0LnggPSBTY3JlZW4ud2lkdGggKiAxMDAwOyBraXQubmFtZSA9IFwiLlVJS2l0XCJcblxuZm9yIGxheWVyIGluIExheWVyLnNlbGVjdEFsbCBcIkAqXCJcblx0cGFyZW50ID0gbGF5ZXIucGFyZW50XG5cdG5hbWUgPSBsYXllci5uYW1lLnJlcGxhY2UgXCJAXCIsIFwiXCJcblx0cGFyZW50W25hbWVdID0gbGF5ZXJcblxuY3VzdG9tQ29tcG9uZW50cyA9IExheWVyLnNlbGVjdEFsbCBcIkN1c3RvbV8qXCJcblxuTGF5ZXI6OmFkZERlc2lnbkNoaWxkcmVuID0gKG9yaWdpbikgLT5cblx0aWYgIW9yaWdpbj8gdGhlbiBvcmlnaW4gPSBAXG5cdGZvciBjaGlsZCBpbiBvcmlnaW4uc2VsZWN0QWxsQ2hpbGRyZW4gKFwiKlwiKVxuXHRcdHBhcmVudCA9IGNoaWxkLnBhcmVudFxuXHRcdHBhcmVudFtjaGlsZC5uYW1lXSA9IGNoaWxkXG5cblxuc3RhdGVDaGFuZ2VQcm9wcyA9IFtcblx0XCJ3aWR0aFwiLCBcImhlaWdodFwiLFxuXHRcIm9wYWNpdHlcIixcblx0XCJzY2FsZVhcIiwgXCJzY2FsZVlcIiwgXCJzY2FsZVpcIiwgXCJzY2FsZVwiLFxuXHRcInNrZXdYXCIsIFwic2tld1lcIiwgXCJza2V3XCIsXG5cdFwicm90YXRpb25YXCIsIFwicm90YXRpb25ZXCIsIFwicm90YXRpb25aXCIsIFwicm90YXRpb25cIixcblx0XCJibHVyXCIsXG5cdFwiYnJpZ2h0bmVzc1wiLCBcInNhdHVyYXRlXCIsIFwiaHVlUm90YXRlXCIsIFwiY29udHJhc3RcIiwgXCJpbnZlcnRcIiwgXCJncmF5c2NhbGVcIiwgXCJzZXBpYVwiLCBcImJsZW5kaW5nXCIsXG5cdFwiYmFja2dyb3VuZEJsdXJcIiwgXCJiYWNrZ3JvdW5kQnJpZ2h0bmVzc1wiLCBcImJhY2tncm91bmRTYXR1cmF0ZVwiLCBcImJhY2tncm91bmRIdWVSb3RhdGVcIiwgXCJiYWNrZ3JvdW5kQ29udHJhc3RcIiwgXCJiYWNrZ3JvdW5kSW52ZXJ0XCIsIFwiYmFja2dyb3VuZEdyYXlzY2FsZVwiLCBcImJhY2tncm91bmRTZXBpYVwiLFxuXHRcInNoYWRvdzFcIiwgXCJzaGFkb3cyXCIsIFwic2hhZG93M1wiLCBcInNoYWRvdzRcIiwgXCJzaGFkb3c1XCIsIFwic2hhZG93NlwiLCBcInNoYWRvdzdcIiwgXCJzaGFkb3c4XCIsIFwic2hhZG93OVwiLFxuXHRcInNoYWRvd1hcIiwgXCJzaGFkb3dZXCIsIFwic2hhZG93Qmx1clwiLCBcInNoYWRvd1NwcmVhZFwiLCBcInNoYWRvd0NvbG9yXCIsIFwic2hhZG93VHlwZVwiLFxuXHRcInNoYWRvd3NcIixcblx0XCJiYWNrZ3JvdW5kQ29sb3JcIiwgXCJjb2xvclwiLFxuXHRcImJvcmRlclJhZGl1c1wiLCBcImJvcmRlckNvbG9yXCIsIFwiYm9yZGVyV2lkdGhcIiwgXCJib3JkZXJTdHlsZVwiLFxuXHRcImltYWdlXCIsIFwiZ3JhZGllbnRcIixcblx0XCJ0ZXh0XCJcbl1cblxuXG5wdXNoUGFyZW50ID0gKGxheWVyLCBkaXJlY3Rpb24pIC0+XG5cdGxheWVyLnB1c2hWYWx1ZXMgPVxuXHRcdG1hcmdpbkJvdHRvbTogbGF5ZXIucGFyZW50LmhlaWdodCAtIGxheWVyLm1heFlcblx0XHRtYXJnaW5SaWdodDogbGF5ZXIucGFyZW50LndpZHRoIC0gbGF5ZXIubWF4WFxuXG5cdGlmIGRpcmVjdGlvbiA9PSBcImRvd25cIlxuXHRcdGxheWVyLm9uQ2hhbmdlIFwieVwiLCAtPlxuXHRcdFx0QHBhcmVudC5oZWlnaHQgPSBsYXllci5tYXhZICsgQHB1c2hWYWx1ZXMubWFyZ2luQm90dG9tXG5cdFx0bGF5ZXIub25DaGFuZ2UgXCJoZWlnaHRcIiwgLT5cblx0XHRcdEBwYXJlbnQuaGVpZ2h0ID0gbGF5ZXIubWF4WSArIEBwdXNoVmFsdWVzLm1hcmdpbkJvdHRvbVxuXG5idWlsZENvbnN0cmFpbnRzUHJvdG9zID0gKGNvbnN0cnVjdG9yTmFtZSkgLT5cblxuXHRjb25zdHJ1Y3Rvck5hbWUgPSBldmFsIGNvbnN0cnVjdG9yTmFtZVxuXHRcblx0Y29uc3RydWN0b3JOYW1lOjpzZXRDb25zdHJhaW50cyA9IChvcHRpb25zPXt9LCBvcmlnaW4pIC0+XG5cdFx0QGNvbnN0cmFpbnRWYWx1ZXMgPVxuXHRcdFx0dG9wOiBpZiB0eXBlb2Ygb3B0aW9ucz8udG9wID09IFwib2JqZWN0XCIgdGhlbiBudWxsIGVsc2UgaWYgb3B0aW9ucz8udG9wPyAmJiB0eXBlb2Ygb3B0aW9ucy50b3AgPT0gXCJudW1iZXJcIiB0aGVuIG9wdGlvbnMudG9wIGVsc2Ugb3JpZ2luPy5jb25zdHJhaW50VmFsdWVzPy50b3AgfHwgbnVsbFxuXHRcdFx0bGVmdDogaWYgdHlwZW9mIG9wdGlvbnM/LmxlZnQgPT0gXCJvYmplY3RcIiB0aGVuIG51bGwgZWxzZSBpZiBvcHRpb25zPy5sZWZ0PyAmJiB0eXBlb2Ygb3B0aW9ucy50b3AgPT0gXCJudW1iZXJcIiB0aGVuIG9wdGlvbnMudG9wIGVsc2Ugb3JpZ2luPy5jb25zdHJhaW50VmFsdWVzPy5sZWZ0IHx8IG51bGxcblx0XHRcdGJvdHRvbTogaWYgdHlwZW9mIG9wdGlvbnM/LmJvdHRvbSA9PSBcIm9iamVjdFwiIHRoZW4gbnVsbCBlbHNlIGlmIG9wdGlvbnM/LnB1c2hEb3duIHRoZW4gbnVsbCBlbHNlIGlmIG9wdGlvbnM/LmJvdHRvbT8gJiYgdHlwZW9mIG9wdGlvbnMuYm90dG9tID09IFwibnVtYmVyXCIgdGhlbiBvcHRpb25zLmJvdHRvbSBlbHNlIG9yaWdpbj8uY29uc3RyYWludFZhbHVlcz8uYm90dG9tIHx8IG51bGxcblx0XHRcdHJpZ2h0OiBpZiB0eXBlb2Ygb3B0aW9ucz8ucmlnaHQgPT0gXCJvYmplY3RcIiB0aGVuIG51bGwgZWxzZSBpZiBvcHRpb25zPy5wdXNoUmlnaHQgdGhlbiBudWxsIGVsc2UgaWYgb3B0aW9ucz8ucmlnaHQ/ICYmIHR5cGVvZiBvcHRpb25zLnJpZ2h0ID09IFwibnVtYmVyXCIgdGhlbiBvcHRpb25zLnJpZ2h0IGVsc2Ugb3JpZ2luPy5jb25zdHJhaW50VmFsdWVzPy5yaWdodCB8fCBudWxsXG5cdFx0XHR3aWR0aDogQHdpZHRoXG5cdFx0XHRoZWlnaHQ6IEBoZWlnaHRcblx0XHRcdHdpZHRoRmFjdG9yOiBvcHRpb25zPy5zY2FsZVggfHwgb3B0aW9ucz8ud2lkdGhGYWN0b3IgfHwgbnVsbFxuXHRcdFx0aGVpZ2h0RmFjdG9yOiBvcHRpb25zPy5zY2FsZVkgfHxvcHRpb25zPy5oZWlnaHRGYWN0b3IgfHwgbnVsbFxuXHRcdFx0Y2VudGVyQW5jaG9yWDogb3B0aW9ucz8uY2VudGVyWCB8fCBvcHRpb25zPy5jZW50ZXJBbmNob3JYIHx8IG51bGxcblx0XHRcdGNlbnRlckFuY2hvclk6IG9wdGlvbnM/LmNlbnRlclkgfHwgb3B0aW9ucz8uY2VudGVyQW5jaG9yWSB8fCBudWxsXG5cdFx0XHRhc3BlY3RSYXRpb0xvY2tlZDogaWYgb3B0aW9ucz8uYXNwZWN0UmF0aW9Mb2NrZWQ/IHRoZW4gb3B0aW9ucy5hc3BlY3RSYXRpb0xvY2tlZCBlbHNlIGlmIG9yaWdpbj8uY29uc3RyYWludFZhbHVlcz8uYXNwZWN0UmF0aW9Mb2NrZWQ/IHRoZW4gb3JpZ2luLmNvbnN0cmFpbnRWYWx1ZXMuYXNwZWN0UmF0aW9Mb2NrZWQgZWxzZSBmYWxzZVxuXG5cdFx0aWYgb3B0aW9ucy5wdXNoRG93bj9cblx0XHRcdEBjb25zdHJhaW50VmFsdWVzLmJvdHRvbSA9IG51bGxcblx0XHRcdHB1c2hQYXJlbnQgQCwgXCJkb3duXCJcblx0XHRpZiBvcHRpb25zLnB1c2hSaWdodD9cblx0XHRcdEBjb25zdHJhaW50VmFsdWVzLnJpZ2h0ID0gbnVsbFxuXHRcdFx0cHVzaFBhcmVudCBALCBcInJpZ2h0XCJcblxuXHRcdGNvbnN0cmFpbnRzID0gQGNvbnN0cmFpbnRWYWx1ZXNcblx0XHR0ZXh0TGF5ZXJBdXRvU2l6ZSA9IHR5cGVvZiBAID09IFRleHRMYXllciAmJiBAYXV0b1NpemVcblxuXHRcdEBvbkNoYW5nZSBcInlcIiwgLT5cblx0XHRcdEBjb25zdHJhaW50VmFsdWVzID0gY29uc3RyYWludHNcblx0XHRAb25DaGFuZ2UgXCJ4XCIsIC0+XG5cdFx0XHRAY29uc3RyYWludFZhbHVlcyA9IGNvbnN0cmFpbnRzXG5cdFx0QG9uQ2hhbmdlIFwiaGVpZ2h0XCIsIC0+XG5cdFx0XHRAY29uc3RyYWludFZhbHVlcyA9IGNvbnN0cmFpbnRzXG5cdFx0QG9uQ2hhbmdlIFwid2lkdGhcIiwgLT5cblx0XHRcdEBjb25zdHJhaW50VmFsdWVzID0gY29uc3RyYWludHNcblxuXHRcdEBhcHBseUNvbnN0cmFpbnRzKClcblxuXHRjb25zdHJ1Y3Rvck5hbWU6OmFwcGx5Q29uc3RyYWludHMgPSAtPlxuXG5cdFx0cmV0dXJuIGlmICFAY29uc3RyYWludFZhbHVlc1xuXG5cdFx0dmFsdWVzID0gQGNvbnN0cmFpbnRWYWx1ZXNcblxuXHRcdGlmICFAcGFyZW50IHRoZW4gcGFyZW50ID0gU2NyZWVuIGVsc2UgcGFyZW50ID0gQHBhcmVudFxuXG5cdFx0YXNwZWN0UmF0aW8gPSBAd2lkdGggLyBAaGVpZ2h0XG5cblx0XHQjIHBvc2l0aW9uXG5cdFx0aWYgdmFsdWVzLnRvcD8gJiYgdHlwZW9mIHZhbHVlcy50b3AgIT0gXCJvYmplY3RcIlxuXHRcdFx0QHkgPSB2YWx1ZXMudG9wXG5cdFx0ZWxzZSBpZiB2YWx1ZXMudG9wID09IG51bGwgJiYgdmFsdWVzLnRvcFJlZj8ubGF5ZXI/XG5cdFx0XHRAeSA9IHZhbHVlcy50b3BSZWYubGF5ZXJbdmFsdWVzLnRvcFJlZi5hbGlnbl0gKyB2YWx1ZXMudG9wUmVmLnZhbHVlXG5cblx0XHRpZiB2YWx1ZXMubGVmdD8gJiYgdHlwZW9mIHZhbHVlcy5sZWZ0ICE9IFwib2JqZWN0XCJcblx0XHRcdEB4ID0gdmFsdWVzLmxlZnRcblx0XHRlbHNlIGlmIHZhbHVlcy5sZWZ0ID09IG51bGwgJiYgdmFsdWVzLmxlZnRSZWY/LmxheWVyP1xuXHRcdFx0QHggPSB2YWx1ZXMubGVmdFJlZi5sYXllclt2YWx1ZXMubGVmdFJlZi5hbGlnbl0gKyB2YWx1ZXMubGVmdFJlZi52YWx1ZVxuXG5cdFx0IyBzaXplXG5cdFx0aWYgdmFsdWVzLmxlZnQ/ICYmIHZhbHVlcy5yaWdodD9cblx0XHRcdEB3aWR0aCA9IHBhcmVudC53aWR0aCAtIEB4IC0gdmFsdWVzLnJpZ2h0XG5cdFx0XHRpZiB2YWx1ZXMuYXNwZWN0UmF0aW9Mb2NrZWRcblx0XHRcdFx0QGhlaWdodCA9IEB3aWR0aCAvIGFzcGVjdFJhdGlvXG5cdFx0aWYgdmFsdWVzLnRvcD8gJiYgdmFsdWVzLmJvdHRvbT9cblx0XHRcdEBoZWlnaHQgPSBwYXJlbnQuaGVpZ2h0IC0gQHkgLSB2YWx1ZXMuYm90dG9tXG5cdFx0XHRpZiB2YWx1ZXMuYXNwZWN0UmF0aW9Mb2NrZWRcblx0XHRcdFx0QHdpZHRoID0gQGhlaWdodCAqIGFzcGVjdFJhdGlvXG5cblx0XHRpZiB2YWx1ZXMud2lkdGhGYWN0b3I/XG5cdFx0XHRAd2lkdGggPSBwYXJlbnQud2lkdGggKiB2YWx1ZXMud2lkdGhGYWN0b3Jcblx0XHRpZiB2YWx1ZXMuaGVpZ2h0RmFjdG9yP1xuXHRcdFx0QGhlaWdodCA9IHBhcmVudC5oZWlnaHQgKiB2YWx1ZXMuaGVpZ2h0RmFjdG9yXG5cblx0XHQjIG1heCBwb3NpdGlvblxuXHRcdGlmIHZhbHVlcy5yaWdodD8gXG5cdFx0XHRAbWF4WCA9IHBhcmVudC53aWR0aCAtIHZhbHVlcy5yaWdodFxuXHRcdGVsc2UgaWYgdmFsdWVzLnJpZ2h0ID09IG51bGwgJiYgdmFsdWVzLnJpZ2h0UmVmPy5sYXllcj9cblx0XHRcdEBtYXhYID0gdmFsdWVzLnJpZ2h0UmVmLmxheWVyW3ZhbHVlcy5yaWdodFJlZi5hbGlnbl0gLSB2YWx1ZXMucmlnaHRSZWYudmFsdWVcblx0XHRpZiB2YWx1ZXMuYm90dG9tP1xuXHRcdFx0QG1heFkgPSBwYXJlbnQuaGVpZ2h0IC0gdmFsdWVzLmJvdHRvbVxuXHRcdGVsc2UgaWYgdmFsdWVzLmJvdHRvbSA9PSBudWxsICYmIHZhbHVlcy5ib3R0b21SZWY/LmxheWVyP1xuXHRcdFx0QG1heFkgPSB2YWx1ZXMuYm90dG9tUmVmLmxheWVyW3ZhbHVlcy5ib3R0b21SZWYuYWxpZ25dIC0gdmFsdWVzLmJvdHRvbVJlZi52YWx1ZVxuXG5cdFx0IyBjZW50ZXIgcG9zaXRpb25cblx0XHRpZiAhdmFsdWVzLmxlZnQ/ICYmICF2YWx1ZXMucmlnaHQ/ICYmIHZhbHVlcy5jZW50ZXJBbmNob3JYP1xuXHRcdFx0QG1pZFggPSBwYXJlbnQud2lkdGggKiB2YWx1ZXMuY2VudGVyQW5jaG9yWFxuXHRcdGlmICF2YWx1ZXMudG9wPyAmJiAhdmFsdWVzLmJvdHRvbT8gJiYgdmFsdWVzLmNlbnRlckFuY2hvclk/XG5cdFx0XHRAbWlkWSA9IHBhcmVudC5oZWlnaHQgKiB2YWx1ZXMuY2VudGVyQW5jaG9yWVxuXG5cdFx0QGNvbnN0cmFpbnRWYWx1ZXMgPSB2YWx1ZXNcblxuXG5sYXllclR5cGVzID0gW1wiTGF5ZXJcIiwgXCJUZXh0TGF5ZXJcIiwgXCJTY3JvbGxDb21wb25lbnRcIiwgXCJQYWdlQ29tcG9uZW50XCIsIFwiU2xpZGVyQ29tcG9uZW50XCIsIFwiUmFuZ2VTbGlkZXJDb21wb25lbnRcIiwgXCJTVkdMYXllclwiLCBcIkJhY2tncm91bmRMYXllclwiLCBcIlNWR1BhdGhcIiwgXCJTVkdHcm91cFwiXVxuZm9yIHR5cGUgaW4gbGF5ZXJUeXBlc1xuXHRidWlsZENvbnN0cmFpbnRzUHJvdG9zKHR5cGUpXG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShMYXllci5wcm90b3R5cGUsIFwiY29uc3RyYWludHNcIiwge1xuXHRnZXQ6IC0+IHJldHVybiBAY29uc3RyYWludFZhbHVlc1xuXHRzZXQ6ICh2YWx1ZSkgLT5cblx0XHRAX2NvbnN0cmFpbnRzID0gdmFsdWVcblx0XHRAZW1pdCBcImNoYW5nZTpjb25zdHJhaW50c1wiLCB2YWx1ZVxuXHRcdEBzZXRDb25zdHJhaW50cyB2YWx1ZVxufSlcblxuZm9yIGNvbXBvbmVudCBpbiBjdXN0b21Db21wb25lbnRzXG5cdG5hbWUgPSBjb21wb25lbnQubmFtZS5yZXBsYWNlIFwiQ3VzdG9tX1wiLCBcIlwiXG5cblx0ZG8gKGNvbXBvbmVudCwgbmFtZSkgLT5cblxuXHRcdGNsYXNzIGV4cG9ydHNbbmFtZV0gZXh0ZW5kcyBMYXllclxuXHRcdFx0Y29uc3RydWN0b3I6IChAb3B0aW9ucz17fSkgLT5cblx0XHRcdFx0c3VwZXIgQG9wdGlvbnNcblx0XHRcdFx0QHByb3BzID0gT2JqZWN0LmFzc2lnbiBjb21wb25lbnQucHJvcHMsIHtwYXJlbnQ6IEBvcHRpb25zLnBhcmVudCB8fCBudWxsfVxuXG5cdFx0XHRcdGlmIEBvcHRpb25zLmNvbnN0cmFpbnRzP1xuXHRcdFx0XHRcdEBjb25zdHJhaW50cyA9IEBvcHRpb25zLmNvbnN0cmFpbnRzXG5cdFx0XHRcdFxuXHRcdFx0XHRAcHJvcHMgPSBAb3B0aW9uc1xuXG5cdFx0XHRcdEBhZGRDaGlsZHJlbigpXG5cdFx0XHRcdEBhc3NpZ25DaGlsZHJlbigpXG5cdFx0XHRcdEBzZXREZXNjZW5kYW50UHJvcHMoKVxuXHRcdFx0XHRAc2V0RGVzY2VuZGFudENvbnN0cmFpbnRzKClcblxuXHRcdFx0XHRAc3RhdGVDb21wb25lbnRzID0gTGF5ZXIuc2VsZWN0QWxsIFwiKlN0YXRlXyN7bmFtZX0qXCJcblx0XHRcdFx0QGFkZFN0YXRlcygpXG5cblx0XHRcdFx0aWYgQG9wdGlvbnMuc3RhdGU/XG5cdFx0XHRcdFx0QGFuaW1hdGVTdGF0ZSBAb3B0aW9ucy5zdGF0ZSwgZmFsc2VcblxuXHRcdFx0YWRkQ2hpbGRyZW46IC0+XG5cdFx0XHRcdG5ld1BhcmVudCA9IGNvbXBvbmVudC5jb3B5KClcblx0XHRcdFx0Zm9yIGNoaWxkIGluIG5ld1BhcmVudC5jaGlsZHJlblxuXHRcdFx0XHRcdGlmIGNoaWxkIGluc3RhbmNlb2YgU1ZHUGF0aCBvciBjaGlsZCBpbnN0YW5jZW9mIFNWR0dyb3VwXG5cdFx0XHRcdFx0XHRVdGlscy50aHJvd0luU3R1ZGlvT3JXYXJuSW5Qcm9kdWN0aW9uIFwiU1ZHICcje2NoaWxkLm5hbWV9JyBpbiAgJ0N1c3RvbV8je25hbWV9JyBtdXN0IGJlIHdyYXBwZWQgaW4gYSBGcmFtZSBpbiBvcmRlciB0byBjcmVhdGUgYSBEZXNpZ24gQ29tcG9uZW50IFN5bWJvbFwiXG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdFx0Y2hpbGQucGFyZW50ID0gQFxuXHRcdFx0XHRcdFx0aWYgY2hpbGQgaW5zdGFuY2VvZiBUZXh0TGF5ZXIgJiYgY29tcG9uZW50LnNlbGVjdENoaWxkKGNoaWxkLm5hbWUpP1xuXHRcdFx0XHRcdFx0XHRjaGlsZC5hdXRvU2l6ZSA9IHRydWVcblx0XHRcdFx0bmV3UGFyZW50LmRlc3Ryb3koKVxuXG5cdFx0XHRhc3NpZ25DaGlsZHJlbjogLT5cblx0XHRcdFx0Zm9yIGRlc2NlbmRhbnQgaW4gQGRlc2NlbmRhbnRzXG5cdFx0XHRcdFx0QFtkZXNjZW5kYW50Lm5hbWVdID0gZGVzY2VuZGFudFxuXG5cdFx0XHRzZXREZXNjZW5kYW50UHJvcHM6IC0+XG5cdFx0XHRcdGZvciBkZXNjZW5kYW50IGluIEBkZXNjZW5kYW50c1xuXHRcdFx0XHRcdGRvIChkZXNjZW5kYW50KSA9PlxuXHRcdFx0XHRcdFx0aWYgQG9wdGlvbnNbZGVzY2VuZGFudC5uYW1lXVxuXHRcdFx0XHRcdFx0XHRAW2Rlc2NlbmRhbnQubmFtZV0uY29uc3RyYWludHMgPSBAb3B0aW9uc1tkZXNjZW5kYW50Lm5hbWVdLmNvbnN0cmFpbnRzIHx8IHVuZGVmaW5lZFxuXHRcdFx0XHRcdFx0XHRAW2Rlc2NlbmRhbnQubmFtZV0ucHJvcHMgPSBAb3B0aW9uc1tkZXNjZW5kYW50Lm5hbWVdXG5cblx0XHRcdHNldERlc2NlbmRhbnRDb25zdHJhaW50czogLT5cblx0XHRcdFx0Zm9yIGRlc2NlbmRhbnQgaW4gQGRlc2NlbmRhbnRzXG5cdFx0XHRcdFx0ZGVjTmFtZSA9IGRlc2NlbmRhbnQubmFtZVxuXHRcdFx0XHRcdG9yaWdpbiA9IGNvbXBvbmVudC5zZWxlY3RDaGlsZCBkZWNOYW1lXG5cdFx0XHRcdFx0ZGVzY2VuZGFudC5zZXRDb25zdHJhaW50cyhcblx0XHRcdFx0XHRcdEBvcHRpb25zW2RlY05hbWVdPy5jb25zdHJhaW50cyB8fCB7fSxcblx0XHRcdFx0XHRcdG9yaWdpblxuXHRcdFx0XHRcdClcblxuXHRcdFx0YWRkU3RhdGVzOiAtPlxuXHRcdFx0XHRAY3VzdG9tU3RhdGVzID1cblx0XHRcdFx0XHRhcnJheTogW11cblxuXHRcdFx0XHRmb3Igc3RhdGUgaW4gQHN0YXRlQ29tcG9uZW50c1xuXHRcdFx0XHRcdGRvIChzdGF0ZSkgPT5cblx0XHRcdFx0XHRcdHN0YXRlSW5kZXggPSBzdGF0ZS5uYW1lLmluZGV4T2YgXCJTdGF0ZVwiXG5cdFx0XHRcdFx0XHRpZiBzdGF0ZUluZGV4ID4gMFxuXHRcdFx0XHRcdFx0XHRzdGF0ZU5hbWUgPSBzdGF0ZS5uYW1lLnNsaWNlIDAsIHN0YXRlSW5kZXgtMVxuXHRcdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdFx0XHRzdGF0ZU5hbWUgPSBzdGF0ZS5uYW1lLnNwbGl0KFwiU3RhdGVfI3tuYW1lfV9cIilbMV1cblxuXHRcdFx0XHRcdFx0QGN1c3RvbVN0YXRlc1tzdGF0ZU5hbWVdID0ge31cblx0XHRcdFx0XHRcdEBjdXN0b21TdGF0ZXMuYXJyYXkucHVzaCBzdGF0ZU5hbWVcblxuXHRcdFx0XHRcdFx0YWRkUHJvcHMgPSAobGF5ZXIsIG9yaWdpbikgLT5cblx0XHRcdFx0XHRcdFx0c3RhdGVQcm9wcyA9IHt9XG5cdFx0XHRcdFx0XHRcdGZvciBwcm9wIGluIHN0YXRlQ2hhbmdlUHJvcHNcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZVByb3BzW3Byb3BdID0gb3JpZ2luW3Byb3BdXG5cdFx0XHRcdFx0XHRcdGxheWVyLnN0YXRlc1tzdGF0ZU5hbWVdID0gc3RhdGVQcm9wc1xuXG5cdFx0XHRcdFx0XHRhZGRQcm9wcyBALCBzdGF0ZVxuXG5cdFx0XHRcdFx0XHRmb3IgZGVzY2VuZGFudCBpbiBzdGF0ZS5kZXNjZW5kYW50c1xuXHRcdFx0XHRcdFx0XHRkbyAoZGVzY2VuZGFudCkgPT5cblx0XHRcdFx0XHRcdFx0XHRhZGRQcm9wcyBAW2Rlc2NlbmRhbnQubmFtZV0sIGRlc2NlbmRhbnRcblxuXHRcdFx0XHRAYWRkU3RhdGVFdmVudHMoKVxuXG5cdFx0XHRhZGRTdGF0ZUV2ZW50czogLT5cblx0XHRcdFx0ZXZlbnRzID0gW11cblxuXHRcdFx0XHRmb3Igc3RhdGUgaW4gQHN0YXRlQ29tcG9uZW50c1xuXHRcdFx0XHRcdGlmIHN0YXRlLm5hbWUuaW5jbHVkZXMgXCJfU3RhdGVfI3tuYW1lfVwiXG5cdFx0XHRcdFx0XHRzdGF0ZU5hbWUgPSBzdGF0ZS5uYW1lLnNwbGl0KFwiX1N0YXRlXyN7bmFtZX1cIilbMF1cblx0XHRcdFx0XHRcdGV2ZW50TmFtZSA9IHN0YXRlLm5hbWUuc3BsaXQoXCJfU3RhdGVfI3tuYW1lfVwiKVsxXVxuXHRcdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRcdGV2ZW50TmFtZSA9IHN0YXRlLm5hbWUucmVwbGFjZSBcIlN0YXRlXyN7bmFtZX1fXCIsIFwiXCJcblx0XHRcdFx0XHRcdHN0YXRlTmFtZSA9IGV2ZW50TmFtZVxuXG5cdFx0XHRcdFx0aWYgZXZlbnROYW1lLmluY2x1ZGVzIFwiX0FuaW1hdGVcIlxuXHRcdFx0XHRcdFx0YW5pbWF0ZSA9IHRydWVcblx0XHRcdFx0XHRcdGV2ZW50TmFtZSA9IGV2ZW50TmFtZS5zcGxpdChcIl9BbmltYXRlXCIpWzBdXG5cdFx0XHRcdFx0ZWxzZSBhbmltYXRlID0gZmFsc2Vcblx0XHRcdFx0XHRcblx0XHRcdFx0XHRldmVudE5hbWUgPSBldmVudE5hbWUucmVwbGFjZSBcIl9cIiwgXCJcIlxuXG5cdFx0XHRcdFx0QGN1c3RvbVN0YXRlc1tzdGF0ZU5hbWVdLmFuaW1hdGUgPSBhbmltYXRlXG5cblx0XHRcdFx0XHR1bmxlc3MgZXZlbnRzLmluY2x1ZGVzIGV2ZW50TmFtZSB0aGVuIGV2ZW50cy5wdXNoIGV2ZW50TmFtZVxuXG5cdFx0XHRcdGZvciBldmVudE5hbWUgaW4gZXZlbnRzXG5cblx0XHRcdFx0XHRkbyAoZXZlbnROYW1lKSA9PlxuXG5cdFx0XHRcdFx0XHRpZiBFdmVudHNbZXZlbnROYW1lXT8gJiYgQGN1c3RvbVN0YXRlcy5hcnJheS5pbmNsdWRlcyBldmVudE5hbWVcblxuXHRcdFx0XHRcdFx0XHRAb24gRXZlbnRzW2V2ZW50TmFtZV0sIChldmVudCwgbGF5ZXIpIC0+XG5cblx0XHRcdFx0XHRcdFx0XHRhbmltYXRlQm9vbCA9IEBjdXN0b21TdGF0ZXNbZXZlbnROYW1lXS5hbmltYXRlXG5cdFx0XHRcdFx0XHRcdFx0QHN0YXRlU3dpdGNoKGV2ZW50TmFtZSwge2FuaW1hdGU6IGFuaW1hdGVCb29sfSlcblx0XHRcdFx0XHRcdFx0XHRAYW5pbWF0ZUNoaWxkcmVuKClcblxuXHRcdFx0XHRcdFx0ZWxzZSBpZiBFdmVudHNbZXZlbnROYW1lXT9cblxuXHRcdFx0XHRcdFx0XHRAb24gRXZlbnRzW2V2ZW50TmFtZV0sIC0+XG5cdFx0XHRcdFx0XHRcdFx0Y3VycmVudEluZGV4ID0gQGN1c3RvbVN0YXRlcy5hcnJheS5pbmRleE9mKEBzdGF0ZXMuY3VycmVudC5uYW1lKVxuXHRcdFx0XHRcdFx0XHRcdG5leHRJbmRleCA9IGN1cnJlbnRJbmRleCArIDFcblx0XHRcdFx0XHRcdFx0XHRpZiBuZXh0SW5kZXggPT0gQGN1c3RvbVN0YXRlcy5hcnJheS5sZW5ndGggdGhlbiBuZXh0SW5kZXggPSAwXG5cdFx0XHRcdFx0XHRcdFx0YW5pbWF0ZUJvb2wgPSBAY3VzdG9tU3RhdGVzW0BjdXN0b21TdGF0ZXMuYXJyYXlbbmV4dEluZGV4XV0uYW5pbWF0ZVxuXHRcdFx0XHRcdFx0XHRcdG5leHRTdGF0ZSA9IEBjdXN0b21TdGF0ZXMuYXJyYXlbbmV4dEluZGV4XVxuXHRcdFx0XHRcdFx0XHRcdFxuXHRcdFx0XHRcdFx0XHRcdEBzdGF0ZVN3aXRjaChuZXh0U3RhdGUsIHthbmltYXRlOiBhbmltYXRlQm9vbH0pXG5cdFx0XHRcdFx0XHRcdFx0QGFuaW1hdGVDaGlsZHJlbigpXG5cblx0XHRcdGFuaW1hdGVDaGlsZHJlbjogKHN0YXRlTmFtZSwgYW5pbWF0ZSwgb3B0aW9ucz17fSkgLT5cblx0XHRcdFx0dW5sZXNzIHN0YXRlTmFtZT8gdGhlbiBzdGF0ZU5hbWUgPSBAc3RhdGVzLmN1cnJlbnQubmFtZVxuXHRcdFx0XHR1bmxlc3MgYW5pbWF0ZT8gdGhlbiBhbmltYXRlID0gQGN1c3RvbVN0YXRlc1tzdGF0ZU5hbWVdLmFuaW1hdGVcblx0XHRcdFx0aWYgIWFuaW1hdGUgdGhlbiBvcHRpb25zLnRpbWUgPSAwXG5cdFx0XHRcdGZvciBkZWMgaW4gQGRlc2NlbmRhbnRzXG5cdFx0XHRcdFx0ZG8gKGRlYykgPT5cblx0XHRcdFx0XHRcdGRlYy5zdGF0ZVN3aXRjaChzdGF0ZU5hbWUsIHthbmltYXRlOiBhbmltYXRlLCBvcHRpb25zOiBvcHRpb25zfSlcblxuXHRcdFx0YW5pbWF0ZVN0YXRlOiAoc3RhdGUsIGFuaW1hdGUsIG9wdGlvbnM9e30pIC0+XG5cblx0XHRcdFx0aWYgIXN0YXRlPyB8fCAhQGN1c3RvbVN0YXRlcz9bc3RhdGVdPyB0aGVuIHJldHVyblxuXHRcdFx0XHRpZiAhYW5pbWF0ZT8gJiYgQGN1c3RvbVN0YXRlcz9bc3RhdGVdPyB0aGVuIGFuaW1hdGUgPSBAY3VzdG9tU3RhdGVzW3N0YXRlXS5hbmltYXRlIGVsc2UgaWYgYW5pbWF0ZT8gdGhlbiBhbmltYXRlID0gYW5pbWF0ZSBlbHNlIGFuaW1hdGUgPSBmYWxzZVxuXHRcdFx0XHRpZiAhYW5pbWF0ZSB0aGVuIG9wdGlvbnMudGltZSA9IDBcblxuXHRcdFx0XHRAc3RhdGVTd2l0Y2goc3RhdGUsIHthbmltYXRlOiBhbmltYXRlLCBvcHRpb25zOiBvcHRpb25zfSlcblx0XHRcdFx0QGFuaW1hdGVDaGlsZHJlbihzdGF0ZSwgYW5pbWF0ZSwgb3B0aW9ucylcblxuXHRcdFx0QGRlZmluZSBcInN0YXRlXCIsXG5cdFx0XHRcdGdldDogLT4gQG9wdGlvbnMuc3RhdGVcblx0XHRcdFx0c2V0OiAodmFsdWUpIC0+XG5cdFx0XHRcdFx0QG9wdGlvbnMuc3RhdGUgPSB2YWx1ZVxuXHRcdFx0XHRcdEBlbWl0KFwiY2hhbmdlOnN0YXRlXCIsIEBvcHRpb25zLnN0YXRlKVxuXHRcdFx0XHRcdEBhbmltYXRlU3RhdGUgdmFsdWVcblxuXG5cbmN1c3RvbVN0YXRlcyA9IExheWVyLnNlbGVjdEFsbCBcIlN0YXRlXypcIlxuXG5mb3IgY29tcG9uZW50U3RhdGUgaW4gY3VzdG9tU3RhdGVzXG5cblx0Y2xhc3NFdmVudE5hbWUgPSBjb21wb25lbnRTdGF0ZS5uYW1lLnJlcGxhY2UgXCJTdGF0ZV9cIiwgXCJcIlxuXHRpZiBjbGFzc0V2ZW50TmFtZS5pbmNsdWRlcyBcIl9cIlxuXHRcdGNsYXNzTmFtZSA9IGNsYXNzRXZlbnROYW1lLnNwbGl0KFwiX1wiKVswXVxuXHRcdGV2ZW50TmFtZSA9IGNsYXNzRXZlbnROYW1lLnNwbGl0KFwiX1wiKVsxXVxuXHRlbHNlXG5cdFx0Y2xhc3NOYW1lID0gY2xhc3NFdmVudE5hbWVcblxuXG4jIyNcbi0tLS0tLS0tLS0tLS0tLS0tLVxuRVhJU1RJTkcgQ0xBU1NFU1xuLS0tLS0tLS0tLS0tLS0tLS0tXG4jIyNcblxuXG5jb21wb25lbnRzID0gTGF5ZXIuc2VsZWN0QWxsIFwiXypcIlxuXG5leHRlbmRTbGlkZXIgPSAob3JpZ2luKSAtPlxuXHRjbGFzcyBleHBvcnRzLlNsaWRlckNvbXBvbmVudCBleHRlbmRzIFNsaWRlckNvbXBvbmVudFxuXG5cdFx0Y29uc3RydWN0b3I6IChAb3B0aW9ucz17fSkgLT5cblx0XHRcdHN1cGVyIEBvcHRpb25zXG5cblx0XHRcdEBrbm9iLnByb3BzID1cblx0XHRcdFx0c2hhZG93czogb3JpZ2luLmtub2Iuc2hhZG93c1xuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9yaWdpbi5rbm9iLmJhY2tncm91bmRDb2xvclxuXHRcdFx0XHRib3JkZXJSYWRpdXM6IG9yaWdpbi5rbm9iLmJvcmRlclJhZGl1c1xuXHRcdFx0XHRmcmFtZTogb3JpZ2luLmtub2IuZnJhbWVcblxuXHRcdFx0QGZpbGwucHJvcHMgPVxuXHRcdFx0XHRzaGFkb3dzOiBvcmlnaW4uZmlsbC5zaGFkb3dzXG5cdFx0XHRcdGJhY2tncm91bmRDb2xvcjogb3JpZ2luLmZpbGwuYmFja2dyb3VuZENvbG9yXG5cdFx0XHRcdGJvcmRlclJhZGl1czogb3JpZ2luLmZpbGwuYm9yZGVyUmFkaXVzXG5cdFx0XHRcdGZyYW1lOiBvcmlnaW4uZmlsbC5mcmFtZVxuXG5cdFx0XHRAcHJvcHMgPVxuXHRcdFx0XHRzaGFkb3dzOiBvcmlnaW4uc2hhZG93c1xuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9yaWdpbi5iYWNrZ3JvdW5kQ29sb3Jcblx0XHRcdFx0Ym9yZGVyUmFkaXVzOiBvcmlnaW4uYm9yZGVyUmFkaXVzXG5cdFx0XHRcdHNpemU6IG9yaWdpbi5zaXplXG5cblx0XHRcdEB2YWx1ZSA9IFV0aWxzLm1vZHVsYXRlIG9yaWdpbi5rbm9iLm1pZFgsIFswLCBvcmlnaW4ud2lkdGhdLCBbQG1pbiwgQG1heF1cblxuXG5leHRlbmRSYW5nZVNsaWRlciA9IChvcmlnaW4pIC0+XG5cdGNsYXNzIGV4cG9ydHMuUmFuZ2VTbGlkZXJDb21wb25lbnQgZXh0ZW5kcyBSYW5nZVNsaWRlckNvbXBvbmVudFxuXG5cdFx0Y29uc3RydWN0b3I6IChAb3B0aW9ucz17fSkgLT5cblx0XHRcdHN1cGVyIEBvcHRpb25zXG5cblx0XHRcdEBtaW5Lbm9iLnByb3BzID1cblx0XHRcdFx0c2hhZG93czogb3JpZ2luLm1pbktub2Iuc2hhZG93c1xuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9yaWdpbi5taW5Lbm9iLmJhY2tncm91bmRDb2xvclxuXHRcdFx0XHRib3JkZXJSYWRpdXM6IG9yaWdpbi5taW5Lbm9iLmJvcmRlclJhZGl1c1xuXHRcdFx0XHRmcmFtZTogb3JpZ2luLm1pbktub2IuZnJhbWVcblx0XHRcdEBtYXhLbm9iLnByb3BzID1cblx0XHRcdFx0c2hhZG93czogb3JpZ2luLm1heEtub2Iuc2hhZG93c1xuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9yaWdpbi5tYXhLbm9iLmJhY2tncm91bmRDb2xvclxuXHRcdFx0XHRib3JkZXJSYWRpdXM6IG9yaWdpbi5tYXhLbm9iLmJvcmRlclJhZGl1c1xuXHRcdFx0XHRmcmFtZTogb3JpZ2luLm1heEtub2IuZnJhbWVcblxuXHRcdFx0QGZpbGwucHJvcHMgPVxuXHRcdFx0XHRzaGFkb3dzOiBvcmlnaW4uZmlsbC5zaGFkb3dzXG5cdFx0XHRcdGJhY2tncm91bmRDb2xvcjogb3JpZ2luLmZpbGwuYmFja2dyb3VuZENvbG9yXG5cdFx0XHRcdGJvcmRlclJhZGl1czogb3JpZ2luLmZpbGwuYm9yZGVyUmFkaXVzXG5cdFx0XHRcdGZyYW1lOiBvcmlnaW4uZmlsbC5mcmFtZVxuXG5cdFx0XHRAcHJvcHMgPVxuXHRcdFx0XHRzaGFkb3dzOiBvcmlnaW4uc2hhZG93c1xuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9yaWdpbi5iYWNrZ3JvdW5kQ29sb3Jcblx0XHRcdFx0Ym9yZGVyUmFkaXVzOiBvcmlnaW4uYm9yZGVyUmFkaXVzXG5cdFx0XHRcdHNpemU6IG9yaWdpbi5zaXplXG5cdFx0XHRcdFxuXHRcdFx0QG1pblZhbHVlID0gVXRpbHMubW9kdWxhdGUgb3JpZ2luLm1pbktub2IubWlkWCwgWzAsIG9yaWdpbi53aWR0aF0sIFtAbWluLCBAbWF4XVxuXHRcdFx0QG1heFZhbHVlID0gVXRpbHMubW9kdWxhdGUgb3JpZ2luLm1heEtub2IubWlkWCwgWzAsIG9yaWdpbi53aWR0aF0sIFtAbWluLCBAbWF4XVxuXG5cblxuZm9yIGNvbXBvbmVudCBpbiBjb21wb25lbnRzXG5cblx0dHlwZSA9IGNvbXBvbmVudC5uYW1lLnJlcGxhY2UgXCJfXCIsIFwiXCJcblxuXHRkbyAoY29tcG9uZW50KSAtPlxuXG5cdFx0Y29tcG9uZW50LmFkZERlc2lnbkNoaWxkcmVuKClcblxuXHRcdGlmIHR5cGUgPT0gXCJTbGlkZXJDb21wb25lbnRcIlxuXHRcdFx0ZXh0ZW5kU2xpZGVyIGNvbXBvbmVudFxuXHRcdGVsc2UgaWYgdHlwZSA9PSBcIlJhbmdlU2xpZGVyQ29tcG9uZW50XCJcblx0XHRcdGV4dGVuZFJhbmdlU2xpZGVyIGNvbXBvbmVudFxuXG5cblxuXG5cblxuXG5cblxuIiwiXG5tb3ZlRnJvbVJlZiA9IChsYXllciwgcmVmZXJlbmNlLCBtb3ZlUmVmLCBsYXllclJlZiwgcmVmVHlwZSkgLT5cblxuXHRvcmlnaW5hbENvbnN0cmFpbnRzID0gbGF5ZXIuY29uc3RyYWludFZhbHVlc1xuXG5cdG9yaWdpbmFsUmVmVmFsdWUgPSByZWZlcmVuY2VbbGF5ZXJSZWZdXG5cdG9yaWdpbmFsTGF5ZXJWYWx1ZSA9IGxheWVyW21vdmVSZWZdXG5cblx0bGF5ZXJbbW92ZVJlZl0gPSByZWZlcmVuY2VbbGF5ZXJSZWZdICsgbGF5ZXIuY29uc3RyYWludFZhbHVlc1tyZWZUeXBlXS52YWx1ZVxuXG5cdCMgcmVmZXJlbmNlLm9uQ2hhbmdlIGxheWVyUmVmLCAodmFsdWUpIC0+XG5cdCMgXHRsYXllclttb3ZlUmVmXSA9IG9yaWdpbmFsTGF5ZXJWYWx1ZSArICh2YWx1ZSAtIG9yaWdpbmFsUmVmVmFsdWUpXG5cblx0bGF5ZXIuY29uc3RyYWludFZhbHVlcyA9IG9yaWdpbmFsQ29uc3RyYWludHNcblxuXG5wdXNoUGFyZW50ID0gKGxheWVyLCBkaXJlY3Rpb24pIC0+XG5cblx0aWYgZGlyZWN0aW9uID09IFwiZG93blwiXG5cdFx0b3JpZ2luYWxZID0gbGF5ZXIueVxuXHRcdG9yaWdpbmFsSGVpZ2h0ID0gbGF5ZXIuaGVpZ2h0XG5cblx0XHRsYXllci5vbkNoYW5nZSBcInlcIiwgKHZhbHVlKSAtPlxuXHRcdFx0QHBhcmVudC5oZWlnaHQgKz0gdmFsdWUgLSBvcmlnaW5hbFlcblx0XHRcdG9yaWdpbmFsWSA9IHZhbHVlXG5cdFx0XHRvcmlnaW5hbEhlaWdodCA9IEBoZWlnaHRcblx0XHRsYXllci5vbkNoYW5nZSBcImhlaWdodFwiLCAodmFsdWUpIC0+XG5cdFx0XHRAcGFyZW50LmhlaWdodCArPSB2YWx1ZSAtIG9yaWdpbmFsSGVpZ2h0XG5cdFx0XHRvcmlnaW5hbFkgPSBAeVxuXHRcdFx0b3JpZ2luYWxIZWlnaHQgPSB2YWx1ZVxuXHRcblx0aWYgZGlyZWN0aW9uID09IFwicmlnaHRcIlxuXHRcdG9yaWdpbmFsWCA9IGxheWVyLnhcblx0XHRvcmlnaW5hbFdpZHRoIC0gbGF5ZXIud2lkdGhcblxuXHRcdGxheWVyLm9uQ2hhbmdlIFwieFwiLCAodmFsdWUpIC0+XG5cdFx0XHRAcGFyZW50LndpZHRoICs9IHZhbHVlIC0gb3JpZ2luYWxYXG5cdFx0XHRvcmlnaW5hbFggPSB2YWx1ZVxuXHRcdFx0b3JpZ2luYWxXaWR0aCA9IEB3aWR0aFxuXHRcdGxheWVyLm9uQ2hhbmdlIFwid2lkdGhcIiwgKHZhbHVlKSAtPlxuXHRcdFx0QHBhcmVudC53aWR0aCArPSB2YWx1ZSAtIG9yaWdpbmFsV2lkdGhcblx0XHRcdG9yaWdpbmFsWCA9IEB4XG5cdFx0XHRvcmlnaW5hbFdpZHRoID0gdmFsdWVcblxuXG5hZGRSZWZlcmVuY2VFdmVudHMgPSAobGF5ZXIpIC0+XG5cblx0b3JpZ2luYWxDb25zdHJhaW50cyA9IGxheWVyLmNvbnN0cmFpbnRWYWx1ZXNcblxuXHRpZiBsYXllci5jb25zdHJhaW50VmFsdWVzPy50b3BSZWY/LmxheWVyPyB8fCBsYXllci5jb25zdHJhaW50VmFsdWVzPy5ib3R0b21SZWY/LmxheWVyP1xuXG5cdFx0cmVmZXJlbmNlID0gbGF5ZXIuY29uc3RyYWludFZhbHVlcz8udG9wUmVmPy5sYXllciB8fCBsYXllci5jb25zdHJhaW50VmFsdWVzPy5ib3R0b21SZWY/LmxheWVyXG5cblx0XHRvcmlnaW5hbFlSZWYgPSByZWZlcmVuY2UueVxuXHRcdG9yaWdpbmFsSGVpZ2h0UmVmID0gcmVmZXJlbmNlLmhlaWdodFxuXHRcdG9yaWdpbmFsWSA9IGxheWVyLnlcblxuXHRcdHJlZmVyZW5jZS5vbkNoYW5nZSBcInlcIiwgKHZhbHVlKSAtPlxuXHRcdFx0bGF5ZXIueSA9IG9yaWdpbmFsWSArICh2YWx1ZSAtIG9yaWdpbmFsWVJlZilcblx0XHRcdG9yaWdpbmFsWVJlZiA9IHZhbHVlXG5cdFx0XHRvcmlnaW5hbFkgPSBsYXllci55XG5cblx0XHR1bmxlc3MgbGF5ZXIuY29uc3RyYWludFZhbHVlcz8udG9wUmVmPy5hbGlnbiA9PSBcInlcIlxuXHRcdFx0cmVmZXJlbmNlLm9uQ2hhbmdlIFwiaGVpZ2h0XCIsICh2YWx1ZSkgLT5cblx0XHRcdFx0bGF5ZXIueSA9IG9yaWdpbmFsWSArICh2YWx1ZSAtIG9yaWdpbmFsSGVpZ2h0UmVmKVxuXHRcdFx0XHRvcmlnaW5hbEhlaWdodFJlZiA9IHZhbHVlXG5cdFx0XHRcdG9yaWdpbmFsWSA9IGxheWVyLnlcblxuXHRcdGlmIGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LnRvcFJlZj8gJiYgbGF5ZXIuY29uc3RyYWludFZhbHVlcz8uYm90dG9tUmVmP1xuXHRcdFx0cmVmZXJlbmNlLm9uQ2hhbmdlIFwiaGVpZ2h0XCIsICh2YWx1ZSkgLT5cblx0XHRcdFx0bGF5ZXIuaGVpZ2h0ID0gdmFsdWUgLSBsYXllci5jb25zdHJhaW50VmFsdWVzPy50b3BSZWYudmFsdWUgLSBsYXllci5jb25zdHJhaW50VmFsdWVzPy5ib3R0b21SZWYudmFsdWVcblx0XHRcdFx0bGF5ZXIueSA9IHJlZmVyZW5jZS55ICsgbGF5ZXIuY29uc3RyYWludFZhbHVlcz8udG9wUmVmLnZhbHVlXG5cdFx0XHRcdG9yaWdpbmFsSGVpZ2h0UmVmID0gdmFsdWVcblxuXHRpZiBsYXllci5jb25zdHJhaW50VmFsdWVzPy5sZWZ0UmVmPy5sYXllcj8gfHwgbGF5ZXIuY29uc3RyYWludFZhbHVlcz8ucmlnaHRSZWY/LmxheWVyP1xuXHRcdHJlZmVyZW5jZSA9IGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LmxlZnRSZWY/LmxheWVyIHx8IGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LnJpZ2h0UmVmPy5sYXllclxuXG5cdFx0b3JpZ2luYWxYUmVmID0gcmVmZXJlbmNlLnhcblx0XHRvcmlnaW5hbFdpZHRoUmVmID0gcmVmZXJlbmNlLndpZHRoXG5cdFx0b3JpZ2luYWxYID0gbGF5ZXIueFxuXG5cdFx0cmVmZXJlbmNlLm9uQ2hhbmdlIFwieFwiLCAodmFsdWUpIC0+XG5cdFx0XHRsYXllci54ID0gb3JpZ2luYWxYICsgKHZhbHVlIC0gb3JpZ2luYWxYUmVmKVxuXHRcdFx0b3JpZ2luYWxYUmVmID0gdmFsdWVcblx0XHRcdG9yaWdpbmFsWCA9IGxheWVyLnhcblxuXHRcdHVubGVzcyBsYXllci5jb25zdHJhaW50VmFsdWVzPy5sZWZ0Py5hbGlnbiA9PSBcInhcIlxuXHRcdFx0cmVmZXJlbmNlLm9uQ2hhbmdlIFwid2lkdGhcIiwgKHZhbHVlKSAtPlxuXHRcdFx0XHRsYXllci54ID0gb3JpZ2luYWxYICsgKHZhbHVlIC0gb3JpZ2luYWxXaWR0aFJlZilcblx0XHRcdFx0b3JpZ2luYWxXaWR0aFJlZiA9IHZhbHVlXG5cdFx0XHRcdG9yaWdpbmFsWCA9IGxheWVyLnhcblxuXHRcdGlmIGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LmxlZnRSZWY/ICYmIGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LnJpZ2h0UmVmP1xuXHRcdFx0cmVmZXJlbmNlLm9uQ2hhbmdlIFwid2lkdGhcIiwgKHZhbHVlKSAtPlxuXHRcdFx0XHRsYXllci53aWR0aCA9IHZhbHVlIC0gbGF5ZXIuY29uc3RyYWludFZhbHVlcz8ubGVmdFJlZi52YWx1ZSAtIGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LnJpZ2h0UmVmLnZhbHVlXG5cdFx0XHRcdGxheWVyLnggPSByZWZlcmVuY2UueCArIGxheWVyLmNvbnN0cmFpbnRWYWx1ZXM/LmxlZnRSZWYudmFsdWVcblx0XHRcdFx0b3JpZ2luYWxXaWR0aFJlZiA9IHZhbHVlXG5cblxuYnVpbGRDb25zdHJhaW50c1Byb3RvcyA9IChjb25zdHJ1Y3Rvck5hbWUpIC0+XG5cblx0Y29uc3RydWN0b3JOYW1lID0gZXZhbCBjb25zdHJ1Y3Rvck5hbWVcblxuXHRjb25zdHJ1Y3Rvck5hbWU6OnNldENvbnN0cmFpbnRzID0gKG9wdGlvbnM9e30sIG9yaWdpbikgLT5cblxuXHRcdEBjb25zdHJhaW50VmFsdWVzID1cblx0XHRcdHRvcDogaWYgdHlwZW9mIG9wdGlvbnMudG9wID09IFwib2JqZWN0XCIgdGhlbiBudWxsIGVsc2UgaWYgb3B0aW9ucy50b3A/IHRoZW4gb3B0aW9ucy50b3AgZWxzZSBpZiBvcmlnaW4/LmNvbnN0cmFpbnRWYWx1ZXM/IHRoZW4gb3JpZ2luLmNvbnN0cmFpbnRWYWx1ZXMudG9wIGVsc2UgbnVsbFxuXHRcdFx0bGVmdDogaWYgdHlwZW9mIG9wdGlvbnMubGVmdCA9PSBcIm9iamVjdFwiIHRoZW4gbnVsbCBlbHNlIGlmIG9wdGlvbnMubGVmdD8gdGhlbiBvcHRpb25zLmxlZnQgZWxzZSBpZiBvcmlnaW4/LmNvbnN0cmFpbnRWYWx1ZXM/IHRoZW4gb3JpZ2luLmNvbnN0cmFpbnRWYWx1ZXMubGVmdCBlbHNlIG51bGxcblx0XHRcdGJvdHRvbTogaWYgdHlwZW9mIG9wdGlvbnMuYm90dG9tID09IFwib2JqZWN0XCIgdGhlbiBudWxsIGVsc2UgaWYgb3B0aW9ucy5wdXNoRG93biB0aGVuIG51bGwgZWxzZSBpZiBvcHRpb25zLmJvdHRvbT8gdGhlbiBvcHRpb25zLmJvdHRvbSBlbHNlIGlmIG9yaWdpbj8uY29uc3RyYWludFZhbHVlcz8gdGhlbiBvcmlnaW4uY29uc3RyYWludFZhbHVlcy5ib3R0b20gZWxzZSBudWxsXG5cdFx0XHRyaWdodDogaWYgdHlwZW9mIG9wdGlvbnMucmlnaHQgPT0gXCJvYmplY3RcIiB0aGVuIG51bGwgZWxzZSBpZiBvcHRpb25zLnB1c2hSaWdodCB0aGVuIG51bGwgIGVsc2UgaWYgb3B0aW9ucy5yaWdodD8gdGhlbiBvcHRpb25zLnJpZ2h0IGVsc2UgaWYgb3JpZ2luPy5jb25zdHJhaW50VmFsdWVzPyB0aGVuIG9yaWdpbi5jb25zdHJhaW50VmFsdWVzLnJpZ2h0IGVsc2UgbnVsbFxuXHRcdFx0d2lkdGg6IEB3aWR0aFxuXHRcdFx0aGVpZ2h0OiBAaGVpZ2h0XG5cdFx0XHR3aWR0aEZhY3RvcjogaWYgb3B0aW9ucy5zY2FsZVg/IHRoZW4gb3B0aW9ucy5zY2FsZVggZWxzZSBpZiBvcHRpb25zLndpZHRoRmFjdG9yPyB0aGVuIG9wdGlvbnMud2lkdGhGYWN0b3IgZWxzZSBudWxsXG5cdFx0XHRoZWlnaHRGYWN0b3I6IGlmIG9wdGlvbnMuc2NhbGVZPyB0aGVuIG9wdGlvbnMuc2NhbGVZIGVsc2UgaWYgb3B0aW9ucy5oZWlnaHRGYWN0b3I/IHRoZW4gb3B0aW9ucy5oZWlnaHRGYWN0b3IgZWxzZSBudWxsXG5cdFx0XHRjZW50ZXJBbmNob3JYOiBpZiBvcHRpb25zLmNlbnRlclg/IHRoZW4gb3B0aW9ucy5jZW50ZXJYIGVsc2UgaWYgb3B0aW9ucy5jZW50ZXJBbmNob3JYPyB0aGVuIG9wdGlvbnMuY2VudGVyQW5jaG9yWCBlbHNlIG51bGxcblx0XHRcdGNlbnRlckFuY2hvclk6IGlmIG9wdGlvbnMuY2VudGVyWT8gdGhlbiBvcHRpb25zLmNlbnRlclkgZWxzZSBpZiBvcHRpb25zLmNlbnRlckFuY2hvclk/IHRoZW4gb3B0aW9ucy5jZW50ZXJBbmNob3JZIGVsc2UgbnVsbFxuXHRcdFx0YXNwZWN0UmF0aW9Mb2NrZWQ6IGlmIG9wdGlvbnMuYXNwZWN0UmF0aW9Mb2NrZWQ/IHRoZW4gb3B0aW9ucy5hc3BlY3RSYXRpb0xvY2tlZCBlbHNlIGlmIG9yaWdpbj8uY29uc3RyYWludFZhbHVlcyB0aGVuIG9yaWdpbi5jb25zdHJhaW50VmFsdWVzLmFzcGVjdFJhdGlvTG9ja2VkIGVsc2UgZmFsc2VcblxuXHRcdCMgcmVzZXRzXG5cdFx0dmFsdWVzID0gQGNvbnN0cmFpbnRWYWx1ZXNcblx0XHRpZiB2YWx1ZXMudG9wPyAmJiB2YWx1ZXMuYm90dG9tP1xuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMuaGVpZ2h0RmFjdG9yID0gbnVsbFxuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMuY2VudGVyQW5jaG9yWSA9IG51bGxcblx0XHRpZiB2YWx1ZXMubGVmdD8gJiYgdmFsdWVzLnJpZ2h0P1xuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMud2lkdGhGYWN0b3IgPSBudWxsXG5cdFx0XHRAY29uc3RyYWludFZhbHVlcy5jZW50ZXJBbmNob3JYID0gbnVsbFxuXHRcdGlmIHZhbHVlcy5sZWZ0PyAmJiB2YWx1ZXMucmlnaHQ/ICYmIHZhbHVlcy50b3A/ICYmIHZhbHVlcy5ib3R0b20/XG5cdFx0XHRAY29uc3RyYWludFZhbHVlcy5hc3BlY3RSYXRpb0xvY2tlZCA9IGZhbHNlXG5cblx0XHRmb3IgcmVmIGluIFtbXCJ0b3BcIiwgXCJ5XCIsIFwibWF4WVwiLCBcInRvcFJlZlwiLCBcImJvdHRvbVwiXSwgW1wibGVmdFwiLCBcInhcIiwgXCJtYXhYXCIsIFwibGVmdFJlZlwiLCBcInJpZ2h0XCJdLCBbXCJib3R0b21cIiwgXCJtYXhZXCIsIFwieVwiLCBcImJvdHRvbVJlZlwiLCBcInRvcFwiXSwgW1wicmlnaHRcIiwgXCJtYXhYXCIsIFwieFwiLCBcInJpZ2h0UmVmXCIsIFwibGVmdFwiXV1cblxuXHRcdFx0aWYgdHlwZW9mIG9wdGlvbnNbcmVmWzBdXSA9PSBcIm9iamVjdFwiICYmIG9wdGlvbnNbcmVmWzBdXSAhPSBudWxsICYmICFvcHRpb25zW3JlZlszXV0/XG5cblx0XHRcdFx0aWYgb3B0aW9uc1tyZWZbMF1dLmxheWVyP1xuXHRcdFx0XHRcdGlmIEBwYXJlbnQ/ICYmIEBwYXJlbnQuc2VsZWN0Q2hpbGQob3B0aW9uc1tyZWZbMF1dLmxheWVyKT9cblx0XHRcdFx0XHRcdGxheWVyID0gQHBhcmVudC5zZWxlY3RDaGlsZCBvcHRpb25zW3JlZlswXV0ubGF5ZXJcblx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0XHRsYXllciA9IExheWVyLnNlbGVjdCBvcHRpb25zW3JlZlswXV0ubGF5ZXJcblx0XHRcdFx0ZWxzZSBsYXllciA9IEBwYXJlbnRcblxuXHRcdFx0XHRhbGlnbiA9IG51bGxcblxuXHRcdFx0XHRpZiAhb3B0aW9uc1tyZWZbMF1dLnZhbHVlPyAmJiBsYXllciA9PSBAcGFyZW50XG5cdFx0XHRcdFx0dmFsdWUgPSBAW3JlZlsxXV1cblx0XHRcdFx0ZWxzZSBpZiBvcHRpb25zW3JlZlswXV0uYWxpZ24/ICYmIG9wdGlvbnNbcmVmWzBdXS52YWx1ZT9cblx0XHRcdFx0XHR2YWx1ZSA9IG9wdGlvbnNbcmVmWzBdXS52YWx1ZVxuXHRcdFx0XHRcdGFsaWduID0gb3B0aW9uc1tyZWZbMF1dLmFsaWduXG5cdFx0XHRcdGVsc2UgaWYgb3B0aW9uc1tyZWZbMF1dLmFsaWduP1xuXHRcdFx0XHRcdHZhbHVlID0gMFxuXHRcdFx0XHRcdGFsaWduID0gb3B0aW9uc1tyZWZbMF1dLmFsaWduXG5cdFx0XHRcdGVsc2UgaWYgIW9wdGlvbnNbcmVmWzBdXS52YWx1ZT8gJiYgIW9wdGlvbnNbcmVmWzBdXS5hbGlnbj9cblx0XHRcdFx0XHR2YWx1ZSA9IEBbcmVmWzFdXSAtIGxheWVyW3JlZlsyXV1cblx0XHRcdFx0XHRhbGlnbiA9IHJlZls0XVxuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0dmFsdWUgPSBvcHRpb25zW3JlZlswXV0udmFsdWVcblx0XHRcdFx0XHRhbGlnbiA9IHJlZls0XVxuXG5cdFx0XHRcdGlmIGFsaWduID09IFwibGVmdFwiIHRoZW4gYWxpZ24gPSBcInhcIlxuXHRcdFx0XHRlbHNlIGlmIGFsaWduID09IFwicmlnaHRcIiB0aGVuIGFsaWduID0gXCJtYXhYXCJcblx0XHRcdFx0ZWxzZSBpZiBhbGlnbiA9PSBcInRvcFwiIHRoZW4gYWxpZ24gPSBcInlcIlxuXHRcdFx0XHRlbHNlIGlmIGFsaWduID09IFwiYm90dG9tXCIgdGhlbiBhbGlnbiA9IFwibWF4WVwiXG5cblx0XHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXNbcmVmWzNdXSA9XG5cdFx0XHRcdFx0bGF5ZXI6IGxheWVyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlXG5cdFx0XHRcdFx0YWxpZ246IGFsaWduXG5cblx0XHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXNbcmVmWzBdXSA9IG51bGxcblx0XHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXNbcmVmWzRdXSA9IG51bGxcblxuXHRcdFx0XHQjIG1vdmVGcm9tUmVmIEAsIGxheWVyLCByZWZbMV0sIHJlZlsyXSwgcmVmWzNdXG5cblx0XHRpZiBvcHRpb25zLnB1c2hEb3duP1xuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMuYm90dG9tID0gbnVsbFxuXHRcdFx0cHVzaFBhcmVudCBALCBcImRvd25cIlxuXHRcdGlmIG9wdGlvbnMucHVzaFJpZ2h0P1xuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMucmlnaHQgPSBudWxsXG5cdFx0XHRwdXNoUGFyZW50IEAsIFwicmlnaHRcIlxuXG5cdFx0dW5sZXNzIG9wdGlvbnMucHVzaERvd24gfHwgQGNvbnN0cmFpbnRWYWx1ZXMudG9wUmVmIHx8IEBjb25zdHJhaW50VmFsdWVzLmJvdHRvbVJlZlxuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMuYm90dG9tID0gaWYgb3B0aW9ucy5ib3R0b20/IHRoZW4gb3B0aW9ucy5ib3R0b20gZWxzZSBpZiBvcmlnaW4/LmNvbnN0cmFpbnRWYWx1ZXM/IHRoZW4gb3JpZ2luLmNvbnN0cmFpbnRWYWx1ZXMuYm90dG9tIGVsc2UgbnVsbFxuXHRcdHVubGVzcyBvcHRpb25zLnB1c2hSaWdodCB8fCBAY29uc3RyYWludFZhbHVlcy5sZWZ0UmVmIHx8IEBjb25zdHJhaW50VmFsdWVzLnJpZ2h0UmVmXG5cdFx0XHRAY29uc3RyYWludFZhbHVlcy5yaWdodCA9IGlmIG9wdGlvbnMucmlnaHQ/IHRoZW4gb3B0aW9ucy5yaWdodCBlbHNlIGlmIG9yaWdpbj8uY29uc3RyYWludFZhbHVlcz8gdGhlbiBvcmlnaW4uY29uc3RyYWludFZhbHVlcy5yaWdodCBlbHNlIG51bGxcblxuXHRcdGlmIEBjb25zdHJhaW50VmFsdWVzLnRvcCA9PSBudWxsICYmIEBjb25zdHJhaW50VmFsdWVzLmJvdHRvbSA9PSBudWxsICYmIEBjb25zdHJhaW50VmFsdWVzLmNlbnRlckFuY2hvclkgPT0gbnVsbCAmJiAhQGNvbnN0cmFpbnRWYWx1ZXMudG9wUmVmICYmICFAY29uc3RyYWludFZhbHVlcy5ib3R0b21SZWZcblx0XHRcdEBjb25zdHJhaW50VmFsdWVzLnRvcCA9IEB5XG5cdFx0aWYgQGNvbnN0cmFpbnRWYWx1ZXMubGVmdCA9PSBudWxsICYmIEBjb25zdHJhaW50VmFsdWVzLnJpZ2h0ID09IG51bGwgJiYgQGNvbnN0cmFpbnRWYWx1ZXMuY2VudGVyQW5jaG9yWCA9PSBudWxsICYmICFAY29uc3RyYWludFZhbHVlcy5sZWZ0UmVmICYmICFAY29uc3RyYWludFZhbHVlcy5yaWdodFJlZlxuXHRcdFx0QGNvbnN0cmFpbnRWYWx1ZXMubGVmdCA9IEB4XG5cblx0XHRAYXBwbHlDb25zdHJhaW50cygpXG5cblxuXHRjb25zdHJ1Y3Rvck5hbWU6OmFwcGx5Q29uc3RyYWludHMgPSAtPlxuXG5cdFx0cmV0dXJuIGlmICFAY29uc3RyYWludFZhbHVlc1xuXG5cdFx0dmFsdWVzID0gQGNvbnN0cmFpbnRWYWx1ZXNcblxuXHRcdGlmICFAcGFyZW50IHRoZW4gcGFyZW50ID0gU2NyZWVuIGVsc2UgcGFyZW50ID0gQHBhcmVudFxuXG5cdFx0YXNwZWN0UmF0aW8gPSBAd2lkdGggLyBAaGVpZ2h0XG5cblx0XHQjIHBvc2l0aW9uXG5cdFx0aWYgdmFsdWVzLnRvcD8gJiYgdHlwZW9mIHZhbHVlcy50b3AgIT0gXCJvYmplY3RcIlxuXHRcdFx0QHkgPSB2YWx1ZXMudG9wXG5cdFx0ZWxzZSBpZiB2YWx1ZXMudG9wID09IG51bGwgJiYgdmFsdWVzLnRvcFJlZj8ubGF5ZXI/XG5cdFx0XHRAeSA9IHZhbHVlcy50b3BSZWYubGF5ZXJbdmFsdWVzLnRvcFJlZi5hbGlnbl0gKyB2YWx1ZXMudG9wUmVmLnZhbHVlXG5cblx0XHRpZiB2YWx1ZXMubGVmdD8gJiYgdHlwZW9mIHZhbHVlcy5sZWZ0ICE9IFwib2JqZWN0XCJcblx0XHRcdEB4ID0gdmFsdWVzLmxlZnRcblx0XHRlbHNlIGlmIHZhbHVlcy5sZWZ0ID09IG51bGwgJiYgdmFsdWVzLmxlZnRSZWY/LmxheWVyP1xuXHRcdFx0QHggPSB2YWx1ZXMubGVmdFJlZi5sYXllclt2YWx1ZXMubGVmdFJlZi5hbGlnbl0gKyB2YWx1ZXMubGVmdFJlZi52YWx1ZVxuXG5cdFx0IyBzaXplXG5cdFx0aWYgdmFsdWVzLmxlZnQ/ICYmIHZhbHVlcy5yaWdodD9cblx0XHRcdEB3aWR0aCA9IHBhcmVudC53aWR0aCAtIEB4IC0gdmFsdWVzLnJpZ2h0XG5cdFx0XHRpZiB2YWx1ZXMuYXNwZWN0UmF0aW9Mb2NrZWRcblx0XHRcdFx0QGhlaWdodCA9IEB3aWR0aCAvIGFzcGVjdFJhdGlvXG5cdFx0aWYgdmFsdWVzLnRvcD8gJiYgdmFsdWVzLmJvdHRvbT9cblx0XHRcdEBoZWlnaHQgPSBwYXJlbnQuaGVpZ2h0IC0gQHkgLSB2YWx1ZXMuYm90dG9tXG5cdFx0XHRpZiB2YWx1ZXMuYXNwZWN0UmF0aW9Mb2NrZWRcblx0XHRcdFx0QHdpZHRoID0gQGhlaWdodCAqIGFzcGVjdFJhdGlvXG5cblx0XHQjIGlmIHZhbHVlcy5sZWZ0UmVmPyAmJiB2YWx1ZXMucmlnaHRSZWY/XG5cdFx0IyBcdEB3aWR0aCA9IHBhcmVudC53aWR0aCAtIHZhbHVlcy5sZWZ0UmVmLnZhbHVlIC0gdmFsdWVzLnJpZ2h0UmVmLnZhbHVlXG5cdFx0IyBpZiB2YWx1ZXMudG9wUmVmPyAmJiB2YWx1ZXMuYm90dG9tUmVmP1xuXHRcdCMgXHRAaGVpZ2h0ID0gcGFyZW50LmhlaWdodCAtIHZhbHVlcy50b3BSZWYudmFsdWUgLSB2YWx1ZXMuYm90dG9tUmVmLnZhbHVlXG5cblx0XHRpZiB2YWx1ZXMud2lkdGhGYWN0b3I/XG5cdFx0XHRAd2lkdGggPSBwYXJlbnQud2lkdGggKiB2YWx1ZXMud2lkdGhGYWN0b3Jcblx0XHRpZiB2YWx1ZXMuaGVpZ2h0RmFjdG9yP1xuXHRcdFx0QGhlaWdodCA9IHBhcmVudC5oZWlnaHQgKiB2YWx1ZXMuaGVpZ2h0RmFjdG9yXG5cblx0XHQjIG1heCBwb3NpdGlvblxuXHRcdGlmIHZhbHVlcy5yaWdodD8gXG5cdFx0XHRAbWF4WCA9IHBhcmVudC53aWR0aCAtIHZhbHVlcy5yaWdodFxuXHRcdGVsc2UgaWYgdmFsdWVzLnJpZ2h0ID09IG51bGwgJiYgdmFsdWVzLnJpZ2h0UmVmPy5sYXllcj9cblx0XHRcdEBtYXhYID0gdmFsdWVzLnJpZ2h0UmVmLmxheWVyW3ZhbHVlcy5yaWdodFJlZi5hbGlnbl0gLSB2YWx1ZXMucmlnaHRSZWYudmFsdWVcblx0XHRpZiB2YWx1ZXMuYm90dG9tP1xuXHRcdFx0QG1heFkgPSBwYXJlbnQuaGVpZ2h0IC0gdmFsdWVzLmJvdHRvbVxuXHRcdGVsc2UgaWYgdmFsdWVzLmJvdHRvbSA9PSBudWxsICYmIHZhbHVlcy5ib3R0b21SZWY/LmxheWVyP1xuXHRcdFx0QG1heFkgPSB2YWx1ZXMuYm90dG9tUmVmLmxheWVyW3ZhbHVlcy5ib3R0b21SZWYuYWxpZ25dIC0gdmFsdWVzLmJvdHRvbVJlZi52YWx1ZVxuXG5cdFx0IyBjZW50ZXIgcG9zaXRpb25cblx0XHRpZiAhdmFsdWVzLmxlZnQ/ICYmICF2YWx1ZXMucmlnaHQ/ICYmIHZhbHVlcy5jZW50ZXJBbmNob3JYP1xuXHRcdFx0QG1pZFggPSBwYXJlbnQud2lkdGggKiB2YWx1ZXMuY2VudGVyQW5jaG9yWFxuXHRcdGlmICF2YWx1ZXMudG9wPyAmJiAhdmFsdWVzLmJvdHRvbT8gJiYgdmFsdWVzLmNlbnRlckFuY2hvclk/XG5cdFx0XHRAbWlkWSA9IHBhcmVudC5oZWlnaHQgKiB2YWx1ZXMuY2VudGVyQW5jaG9yWVxuXG5cdFx0QGNvbnN0cmFpbnRWYWx1ZXMgPSB2YWx1ZXNcblxuXHRcdGFkZFJlZmVyZW5jZUV2ZW50cyhAKVxuXG5cbmxheWVyVHlwZXMgPSBbXCJMYXllclwiLCBcIlRleHRMYXllclwiLCBcIlNjcm9sbENvbXBvbmVudFwiLCBcIlBhZ2VDb21wb25lbnRcIiwgXCJTbGlkZXJDb21wb25lbnRcIiwgXCJSYW5nZVNsaWRlckNvbXBvbmVudFwiLCBcIlNWR0xheWVyXCIsIFwiQmFja2dyb3VuZExheWVyXCIsIFwiU1ZHUGF0aFwiLCBcIlNWR0dyb3VwXCJdXG5mb3IgdHlwZSBpbiBsYXllclR5cGVzXG5cdGJ1aWxkQ29uc3RyYWludHNQcm90b3ModHlwZSlcblxuXG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShMYXllci5wcm90b3R5cGUsIFwiY29uc3RyYWludHNcIiwge1xuXG5cdGdldDogLT4gcmV0dXJuIEBfY29uc3RyYWludHNcblx0c2V0OiAodmFsdWUpIC0+XG5cdFx0QF9jb25zdHJhaW50cyA9IHZhbHVlXG5cdFx0QGVtaXQgXCJjaGFuZ2U6Y29uc3RyYWludHNcIiwgdmFsdWVcblx0XHRAc2V0Q29uc3RyYWludHMgdmFsdWVcblxufSkiLCIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUVBQTtBRENBLElBQUE7O0FBQUEsV0FBQSxHQUFjLFNBQUMsS0FBRCxFQUFRLFNBQVIsRUFBbUIsT0FBbkIsRUFBNEIsUUFBNUIsRUFBc0MsT0FBdEM7QUFFYixNQUFBO0VBQUEsbUJBQUEsR0FBc0IsS0FBSyxDQUFDO0VBRTVCLGdCQUFBLEdBQW1CLFNBQVUsQ0FBQSxRQUFBO0VBQzdCLGtCQUFBLEdBQXFCLEtBQU0sQ0FBQSxPQUFBO0VBRTNCLEtBQU0sQ0FBQSxPQUFBLENBQU4sR0FBaUIsU0FBVSxDQUFBLFFBQUEsQ0FBVixHQUFzQixLQUFLLENBQUMsZ0JBQWlCLENBQUEsT0FBQSxDQUFRLENBQUM7U0FLdkUsS0FBSyxDQUFDLGdCQUFOLEdBQXlCO0FBWlo7O0FBZWQsVUFBQSxHQUFhLFNBQUMsS0FBRCxFQUFRLFNBQVI7QUFFWixNQUFBO0VBQUEsSUFBRyxTQUFBLEtBQWEsTUFBaEI7SUFDQyxTQUFBLEdBQVksS0FBSyxDQUFDO0lBQ2xCLGNBQUEsR0FBaUIsS0FBSyxDQUFDO0lBRXZCLEtBQUssQ0FBQyxRQUFOLENBQWUsR0FBZixFQUFvQixTQUFDLEtBQUQ7TUFDbkIsSUFBQyxDQUFBLE1BQU0sQ0FBQyxNQUFSLElBQWtCLEtBQUEsR0FBUTtNQUMxQixTQUFBLEdBQVk7YUFDWixjQUFBLEdBQWlCLElBQUMsQ0FBQTtJQUhDLENBQXBCO0lBSUEsS0FBSyxDQUFDLFFBQU4sQ0FBZSxRQUFmLEVBQXlCLFNBQUMsS0FBRDtNQUN4QixJQUFDLENBQUEsTUFBTSxDQUFDLE1BQVIsSUFBa0IsS0FBQSxHQUFRO01BQzFCLFNBQUEsR0FBWSxJQUFDLENBQUE7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 846 | --------------------------------------------------------------------------------