angular-upcrop
Version:
Library with upload and crop feature for Angular 6+
811 lines (786 loc) • 88.4 kB
JavaScript
import { Component, Input, Output, EventEmitter, ViewChild, Inject, Injectable, Directive, ElementRef, Renderer2, NgModule } from '@angular/core';
import { FileUploader, FileUploadModule } from 'ng2-file-upload';
import { AngularCropperjsModule } from 'angular-cropperjs';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatIconModule, MatButtonModule, MatCardModule, MatTooltipModule } from '@angular/material';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropUploadComponent {
constructor() {
this.config = {};
this.uploadQueue = [];
this.onUploadQueue = new EventEmitter();
this.onUploadImage = new EventEmitter();
this.uploader = new FileUploader({});
this.hasFileOver = false;
}
/**
* @return {?}
*/
ngOnInit() {
//
// Set uploader
this.setUploader();
}
/**
* Set uploader
* @return {?}
*/
setUploader() {
//
// Set uploader
this.uploader.setOptions({ url: this.config.url, authToken: this.config.authToken, autoUpload: this.config.autoUpload, additionalParameter: this.config.additionalParameter });
//
// After add file event
this.uploader.onAfterAddingFile = (file) => {
//
// Set with credentials
file.withCredentials = this.config.withCredentials;
//
// Emit onUploadQueue
this.onUploadQueue.emit({
file: file
});
};
//
// On success item event
this.uploader.onSuccessItem = (item, response, status, headers) => {
if (status == 200) {
/** @type {?} */
let data = JSON.parse(response);
//
// Emit onUploadQueue
this.onUploadImage.emit({
data: data
});
}
};
}
/**
* On file over event
* @param {?} e
* @return {?}
*/
onFileOver(e) {
this.hasFileOver = e;
}
/**
* Truncate filename
* @param {?} n
* @param {?} len
* @return {?}
*/
truncate(n, len) {
//
// Validate
if (!n)
return n;
/** @type {?} */
let ext = n.substring(n.lastIndexOf(".") + 1, n.length).toLowerCase();
/** @type {?} */
let filename = n.replace('.' + ext, '');
if (filename.length <= len) {
return n;
}
filename = filename.substr(0, len) + (n.length > len ? '[...]' : '');
return filename + '.' + ext;
}
}
UpcropUploadComponent.decorators = [
{ type: Component, args: [{
selector: 'upcrop-upload',
template: `<label ng2FileDrop multiple class="my-drop-zone" [ngClass]="{'nv-file-over': hasFileOver}" (fileOver)="onFileOver($event)"
[uploader]="uploader" fxLayout fxLayoutAlign="center center">
Área de upload
<input type="file" ng2FileSelect multiple [uploader]="uploader" style="display: none" />
</label>
<!-- FILES -->
<table class="table upcrop-upload-table">
<thead>
<tr>
<th>Preview</th>
<th>Arquivo</th>
<th style="width:30px; text-align: center">
<mat-icon class="is-pulled-right">settings</mat-icon>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td class="image-preview" style="width:100px">
<img upcropImagePreview [image]="item?._file" class="media-object" />
</td>
<td>{{ truncate(item?.file?.name, 16) }}</td>
<td class="actions" style="width:30px">
<button class="danger-btn" mat-icon-button color="warn" (click)="item.remove()">
<mat-icon>delete</mat-icon>
</button>
</td>
</tr>
<tr [hidden]="uploader.queue.length">
<td colspan="3" class="has-text-danger">
Nenhum arquivo, adicione acima.
</td>
</tr>
</tbody>
</table>
`,
styles: [`.my-drop-zone{border:2px dashed rgba(0,0,0,.04);width:100%;display:flex;padding:20px;background-color:rgba(0,0,0,.04);color:rgba(0,0,0,.7)}.nv-file-over{border:2px dashed rgba(244,67,54,.4)}[upcropImagePreview]{display:block}.upcrop-upload-table{background-color:#fff;color:#363636;border-collapse:collapse;border-spacing:0;width:100%;margin-bottom:0}.upcrop-upload-table td,.upcrop-upload-table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.upcrop-upload-table td.is-white,.upcrop-upload-table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.upcrop-upload-table td.is-black,.upcrop-upload-table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.upcrop-upload-table td.is-light,.upcrop-upload-table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.upcrop-upload-table td.is-dark,.upcrop-upload-table th.is-dark{background-color:#363636;border-color:#363636;color:#f5f5f5}.upcrop-upload-table td.is-primary,.upcrop-upload-table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.upcrop-upload-table td.is-info,.upcrop-upload-table th.is-info{background-color:#3273dc;border-color:#3273dc;color:#fff}.upcrop-upload-table td.is-success,.upcrop-upload-table th.is-success{background-color:#23d160;border-color:#23d160;color:#fff}.upcrop-upload-table td.is-warning,.upcrop-upload-table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,.7)}.upcrop-upload-table td.is-danger,.upcrop-upload-table th.is-danger{background-color:#ff3860;border-color:#ff3860;color:#fff}.upcrop-upload-table td.is-narrow,.upcrop-upload-table th.is-narrow{white-space:nowrap;width:1%}.upcrop-upload-table th{color:#363636;text-align:left}.upcrop-upload-table tr:hover{background-color:#fafafa}.upcrop-upload-table tr.is-selected{background-color:#00d1b2;color:#fff}.upcrop-upload-table tr.is-selected a,.upcrop-upload-table tr.is-selected strong{color:currentColor}.upcrop-upload-table tr.is-selected td,.upcrop-upload-table tr.is-selected th{border-color:#fff;color:currentColor}.upcrop-upload-table tfoot td,.upcrop-upload-table tfoot th{border-width:2px 0 0;color:#363636}.upcrop-upload-table tbody tr:last-child td,.upcrop-upload-table tbody tr:last-child th{border-bottom-width:0}.upcrop-upload-table.is-bordered td,.upcrop-upload-table.is-bordered th{border-width:1px}.upcrop-upload-table.is-bordered tr:last-child td,.upcrop-upload-table.is-bordered tr:last-child th{border-bottom-width:1px}.upcrop-upload-table.is-fullwidth{width:100%}.upcrop-upload-table.is-narrow td,.upcrop-upload-table.is-narrow th{padding:.25em .5em}.upcrop-upload-table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.upcrop-upload-table.is-striped tbody tr:not(.is-selected):nth-child(even):hover{background-color:#f5f5f5}td,th{padding:0;text-align:left}.upcrop-upload-table-search{display:flex;padding:1.3em 1.6em}.upcrop-upload-table-search input{font-size:14px;flex:1 1 100%;box-sizing:border-box;-webkit-box-flex:1;border:none;background-color:transparent;outline:-webkit-focus-ring-color auto 0!important}.upcrop-upload-table-search>mat-icon{margin-right:16px;margin-top:2px}[table-loading]{position:absolute;width:100%;margin-top:59px!important;background-color:rgba(255,255,255,.9);height:calc(100% - 59px);z-index:1}[table-no-entries]{padding:1.6em}.mat-card[has-table]{padding:0}.mat-card[has-table] .mat-card-actions{padding:8px!important;margin:0;border-top:1px solid #dbdbdb;border-color:rgba(0,0,0,.09)}.mat-card[has-table] .mat-card-actions .mat-icon-button{color:rgba(0,0,0,.54)}.mat-card[has-table] .mat-card-actions .mat-icon-button[disabled]{color:rgba(0,0,0,.18)}.mat-card[has-table] .mat-card-actions .mat-paginator-page-size-label{margin:0 15px;color:rgba(0,0,0,.54);font-size:12px;font-weight:400}.upcrop-upload-table .actions .mat-icon-button{height:30px!important;width:30px;line-height:30px;flex-direction:column;box-sizing:border-box;display:flex;max-width:100%;place-content:center;align-items:center}.upcrop-upload-table .actions .mat-icon-button .mat-icon{font-size:18px;line-height:18px;width:18px;height:18px}.upcrop-upload-table thead tr{background-color:rgba(0,0,0,.04)!important}.upcrop-upload-table thead td:first-of-type,.upcrop-upload-table thead th:first-of-type{padding-left:1.8em}.upcrop-upload-table thead td:last-of-type,.upcrop-upload-table thead th:last-of-type{padding-right:1.8em}.upcrop-upload-table thead td mat-icon,.upcrop-upload-table thead th mat-icon{height:16px;width:16px;line-height:16px;font-size:16px;vertical-align:bottom;margin-right:3px}.upcrop-upload-table tbody td,.upcrop-upload-table tbody th{border-color:rgba(0,0,0,.04)}.upcrop-upload-table tbody td:first-of-type,.upcrop-upload-table tbody th:first-of-type{padding-left:1.6em}.upcrop-upload-table tbody td:last-of-type,.upcrop-upload-table tbody th:last-of-type{padding-right:1.6em}.upcrop-upload-table thead td,.upcrop-upload-table thead th{color:rgba(0,0,0,.54);font-size:12px;font-weight:400;padding:1.3em .75em;border:0}.upcrop-upload-table tbody td{color:rgba(0,0,0,.87);padding:1em .75em;font-size:.9rem;font-weight:400}@media (max-width:800px){.upcrop-upload-table{display:inline-block;vertical-align:top;max-width:100%;overflow-x:auto;white-space:nowrap;border-collapse:collapse;border-spacing:0;display:flex;overflow:hidden;background:0 0}.upcrop-upload-table .actions a{margin-top:-.35em}.upcrop-upload-table .is-pulled-right{float:none!important}.upcrop-upload-table thead{display:flex;flex-shrink:0;min-width:-webkit-min-content;min-width:-moz-min-content;min-width:min-content}.upcrop-upload-table thead td,.upcrop-upload-table thead th{padding:1.3em 1.8em;text-align:right;width:100%!important}.upcrop-upload-table thead td mat-icon,.upcrop-upload-table thead th mat-icon{margin-right:0}.upcrop-upload-table tbody{flex:1 1 100%;box-sizing:border-box;-webkit-box-flex:1;-webkit-overflow-scrolling:touch;background:radial-gradient(left,ellipse,rgba(0,0,0,.2) 0,transparent 75%) 0 center,radial-gradient(right,ellipse,rgba(0,0,0,.2) 0,transparent 75%) 100% center;background-size:10px 100%,10px 100%;background-attachment:scroll,scroll;background-repeat:no-repeat;display:flex;position:relative;overflow-x:auto;overflow-y:hidden;margin-right:1.6em}.upcrop-upload-table tbody tr{flex:1 1 100%;box-sizing:border-box;-webkit-box-flex:1}.upcrop-upload-table tbody td,.upcrop-upload-table tbody th{padding:1.155em 1.6em;text-align:left!important}.upcrop-upload-table tbody td:first-of-type,.upcrop-upload-table tbody th:first-of-type{padding-left:1.6em}.upcrop-upload-table tbody td:last-of-type,.upcrop-upload-table tbody th:last-of-type{padding-right:1.6em}.upcrop-upload-table tr{display:flex;flex-direction:column;min-width:-webkit-min-content;min-width:-moz-min-content;min-width:min-content;flex-shrink:0}.upcrop-upload-table td,.upcrop-upload-table th{display:block;background-image:none!important;border-left:0}.upcrop-upload-table td:first-child,.upcrop-upload-table th:first-child{background-image:linear-gradient(to right,#fff 50%,rgba(255,255,255,0) 100%);background-repeat:no-repeat;background-size:20px 100%}.upcrop-upload-table td:last-child,.upcrop-upload-table th:last-child{background-image:linear-gradient(to left,#fff 50%,rgba(255,255,255,0) 100%);background-repeat:no-repeat;background-position:100% 0;background-size:20px 100%}.upcrop-upload-table td:not(:last-child),.upcrop-upload-table th:not(:last-child){border-bottom:0}}.upcrop-upload-table ::-webkit-scrollbar{height:8px;overflow:visible;width:16px}.upcrop-upload-table ::-webkit-scrollbar-button{height:0;width:0}.upcrop-upload-table ::-webkit-scrollbar-corner{background:0 0}.upcrop-upload-table ::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.2);background-clip:padding-box;border:solid transparent;border-width:1px 1px 1px 6px;min-height:28px;padding:100px 0 0;box-shadow:inset 1px 1px 0 rgba(0,0,0,.1),inset 0 -1px 0 rgba(0,0,0,.07)}.upcrop-upload-table ::-webkit-scrollbar-track{background-clip:padding-box;border:solid transparent;border-width:0 0 0 4px}[enterlist] [has-table]{margin-right:-24px;margin-left:-24px}[enterlist] [has-table] .upcrop-upload-table{background-color:transparent}[enterlist] [has-table] .upcrop-upload-table thead tr{background-color:rgba(0,0,0,.02)!important}[enterlist] [has-table] .upcrop-upload-table tr:hover{background-color:inherit}.image-preview img{max-width:100%}`]
},] },
];
/** @nocollapse */
UpcropUploadComponent.ctorParameters = () => [];
UpcropUploadComponent.propDecorators = {
config: [{ type: Input }],
uploadQueue: [{ type: Input }],
onUploadQueue: [{ type: Output }],
onUploadImage: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropCropComponent {
constructor() {
this.config = {};
this.uploader = [];
this.onCropImage = new EventEmitter();
this.uploading = false;
this.current = false;
this.currentNumber = false;
}
/**
* @return {?}
*/
ngOnInit() {
}
/**
* Set cropping
* set cropping and everything to start crop
* @param {?} uploader
* @return {?}
*/
setCropping(uploader) {
//
// Disable cropping
this.current = false;
this.currentNumber = false;
//
// Set uploader
this.uploader = uploader;
//
// Set queue for crop
this.uploader.queue;
//
// Get next crop in the queue
this.goToNextCrop();
}
/**
* Unset cropping
* @return {?}
*/
unsetCropping() {
this.angularCropper.cropper.destroy();
this.current = false;
}
/**
* Go to next crop
* @return {?}
*/
goToNextCrop() {
//
// Validate file
if (!this.uploader.queue.length)
return;
//
// Update counter and file
if (this.currentNumber === false) {
this.currentNumber = 0;
}
else {
this.emitOnCropImage();
//
// Unset cropping
this.unsetCropping();
//
// Update counter
this.currentNumber++;
}
//
// Get next crop in the queue
this.current = this.uploader.queue[this.currentNumber];
/** @type {?} */
let reader = new FileReader();
//
// Callback for reader.readAsDataUrl() below
reader.onloadend = (e) => {
//
// Set _dataUrl
this.current._dataUrl = reader.result;
};
//
// Get data url
reader.readAsDataURL(this.current._file);
}
/**
* Emit on crop image
* @return {?}
*/
emitOnCropImage() {
//
// Add image data to current file
this.onCropImage.emit({
data: this.angularCropper.cropper.getData(),
file: this.currentNumber
});
}
/**
* Zoom in
* @return {?}
*/
zoomIn() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.zoom(0.1);
}
/**
* Zoom out
* @return {?}
*/
zoomOut() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.zoom(-0.1);
}
/**
* Go left
* @return {?}
*/
goLeft() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.move(-10, 0);
}
/**
* Go right
* @return {?}
*/
goRight() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.move(10, 0);
}
/**
* Go up
* @return {?}
*/
goUp() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.move(0, -10);
}
/**
* Go down
* @return {?}
*/
goDown() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.move(0, 10);
}
/**
* Rotate left
* @return {?}
*/
rotateLeft() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.rotate(-45);
}
/**
* Rotate right
* @return {?}
*/
rotateRight() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.rotate(45);
}
/**
* Reset
* @return {?}
*/
reset() {
//
// Validate
if (!this.angularCropper || !this.angularCropper.cropper)
return;
//
// Action
this.angularCropper.cropper.reset();
}
}
UpcropCropComponent.decorators = [
{ type: Component, args: [{
selector: 'upcrop-crop',
template: `<!-- MAIN LOAD -->
<div class="crop-loading" [fxHide]="!uploading">
<div class="spinner"></div>
</div>
<div [hidden]="uploading" class="upcrop-crop">
<h2 class="has-text-centered mat-subheading-2">Imagem {{currentNumber + 1}} de {{uploader?.queue?.length}}</h2>
<div class="crop-image-container">
<angular-cropper #angularCropper *ngIf="current && current._dataUrl" [cropperOptions]="config" [imageUrl]="current?._dataUrl"></angular-cropper>
</div>
<!--CROPPER CONTROLS-->
<div class="crop-controls" fxLayout fxLayoutAlign="center center" fxLayoutWrap *ngIf="current && current._dataUrl">
<button mat-button (click)="zoomIn()" class="mat-icon-button" aria-label="Aumentar zoom" mdTooltip="Aumentar zoom">
<mat-icon>zoom_in</mat-icon>
</button>
<button mat-button (click)="zoomOut()" class="mat-icon-button" aria-label="Diminuir zoom" mdTooltip="Diminuir zoom">
<mat-icon>zoom_out</mat-icon>
</button>
<button mat-button (click)="goLeft()" class="mat-icon-button" aria-label="Mover para esquerda" mdTooltip="Mover para esquerda">
<mat-icon>keyboard_arrow_left</mat-icon>
</button>
<button mat-button (click)="goRight()" class="mat-icon-button" aria-label="Mover para direita" mdTooltip="Mover para direita">
<mat-icon>keyboard_arrow_right</mat-icon>
</button>
<button mat-button (click)="goUp()" class="mat-icon-button" aria-label="Mover para cima" mdTooltip="Mover para cima">
<mat-icon>keyboard_arrow_up</mat-icon>
</button>
<button mat-button (click)="goDown()" class="mat-icon-button" aria-label="Mover para baixo" mdTooltip="Mover para baixo">
<mat-icon>keyboard_arrow_down</mat-icon>
</button>
<button mat-button (click)="reset()" class="mat-icon-button mat-primary" aria-label="Restaurar imagem original" mdTooltip="Restaurar imagem original">
<mat-icon>cached</mat-icon>
</button>
</div>
</div>
`,
styles: [`.crop-image-container{max-height:500px;width:100%}.crop-image-container img{max-width:100%;max-height:100%}.crop-controls{padding-top:20px;padding-bottom:20px}.crop-loading{min-height:120px;padding-top:34px;margin:100px 24px;box-sizing:border-box;flex-direction:column;max-width:100%;place-content:center;align-items:center;display:flex}.crop-loading .spinner{margin-top:-20px;border:4px solid rgba(0,0,0,.06);border-top:4px solid #2196f3;border-radius:50%;width:50px;height:50px;-webkit-animation:1.1s linear infinite spin;animation:1.1s linear infinite spin}.upcrop-crop .has-text-centered{text-align:center!important}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}`]
},] },
];
/** @nocollapse */
UpcropCropComponent.ctorParameters = () => [];
UpcropCropComponent.propDecorators = {
angularCropper: [{ type: ViewChild, args: ['angularCropper',] }],
config: [{ type: Input }],
uploader: [{ type: Input }],
onCropImage: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropDialogComponent {
/**
* @param {?} dialogRef
* @param {?} data
*/
constructor(dialogRef, data) {
this.dialogRef = dialogRef;
this.data = data;
this.cropData = {};
this.uploadedImages = [];
this.uploader = null;
this.steps = {
total: 2,
options: [{
label: 'Subir imagens',
number: 1,
next: 2,
nextDisabled: () => { return this.step1NextDisabled(); },
nextAction: () => { this.goToStep2(); }
}, {
label: 'Cortar imagens',
number: 2,
previus: 1,
previusAction: () => { this.goToStep1(); }
}],
current: {}
};
}
/**
* @return {?}
*/
ngOnInit() {
//
// Set first step
this.steps.current = this.steps.options[0];
}
/**
* Go to step 1
* @return {?}
*/
goToStep1() {
//
// Reset crop
this.upcropCrop.unsetCropping();
//
// Change to step 1
this.steps.current = this.steps.options[0];
//
// Reset crop
this.upcropCrop.current = false;
this.upcropCrop.currentNumber = false;
}
/**
* Go to step 2
* @return {?}
*/
goToStep2() {
//
// Change to step 2
this.steps.current = this.steps.options[1];
//
// Set crop
this.upcropCrop.setCropping(this.upcropUpload.uploader);
}
/**
* Finish
* @return {?}
*/
finish() {
//
// On complete all files uplaod
this.upcropUpload.uploader.onCompleteAll = () => {
//
// Remove loading
this.upcropCrop.uploading = false;
//
// Close dialog with uploadedImages
this.dialogRef.close(this.uploadedImages);
};
//
// Emit on crop image
this.upcropCrop.emitOnCropImage();
//
// Set crop data in additionalParameter
this.upcropUpload.uploader.options.additionalParameter['cropData'] = this.cropData;
//
// Upload all
this.upcropCrop.uploading = true;
this.upcropUpload.uploader.uploadAll();
}
/**
* Step 1 next button disabled conditions
* @return {?}
*/
step1NextDisabled() {
return !this.upcropUpload.uploader.queue.length;
}
/**
* On crop image event
* @param {?} event
* @return {?}
*/
onCropImage(event) {
/** @type {?} */
const cropData = this.createUrlParams(event.data);
//
// Add crop to uploader file crop data
this.upcropUpload.uploader.queue[event.file].url = this.data.uploadConfig.url + cropData;
}
/**
* On upload image event
* @param {?} event
* @return {?}
*/
onUploadImage(event) {
this.uploadedImages.push(event);
}
/**
* Create url params
* @param {?} obj
* @return {?}
*/
createUrlParams(obj) {
//
// Validate obj
if (!obj)
return '';
/** @type {?} */
const url = '?';
/** @type {?} */
const params = Object.keys(obj).map(function (key) {
return key + '=' + encodeURIComponent(obj[key]);
}).join('&');
return url + params;
}
}
UpcropDialogComponent.decorators = [
{ type: Component, args: [{
selector: 'upcrop-dialog',
template: `<h2 mat-dialog-title class="has-text-danger">
Upload de imagens
<small>com corte</small>
</h2>
<mat-dialog-content>
<!-- STEPS -->
<div steps>
<div steps-content fxLayout="row" fxLayoutAlign="start center">
<button mat-icon-button fxHide.xs [disabled]="!steps.current.previus || (steps.current.previusDisabled && steps.current.previusDisabled())"
(click)="steps.current.previusAction()">
<mat-icon>keyboard_arrow_left</mat-icon>
</button>
<span fxFlex></span>
<h3>Passo
<b>{{steps.current.number}}</b> de
<b>{{steps.total}}</b> /
<span class="has-text-primary">{{steps.current.label}}</span>
</h3>
<span fxFlex></span>
<button mat-icon-button fxHide.xs [disabled]="!steps.current.next || (steps.current.nextDisabled && steps.current.nextDisabled())"
(click)="steps.current.nextAction()">
<mat-icon>keyboard_arrow_right</mat-icon>
</button>
</div>
</div>
<!-- STEP 1 / UPLOAD -->
<div class="step-1" [hidden]="steps.current.number != 1">
<upcrop-upload #upcropUpload [config]="data.uploadConfig" (onUploadImage)="onUploadImage($event)"></upcrop-upload>
</div>
<!-- STEP 2 / CROP -->
<div class="step-2" [hidden]="steps.current.number != 2">
<upcrop-crop #upcropCrop [config]="data.cropConfig" (onCropImage)="onCropImage($event)"></upcrop-crop>
</div>
</mat-dialog-content>
<mat-dialog-actions *ngIf="steps.current.number == 1">
<button mat-button mat-dialog-close>Fechar</button>
<button mat-button color="primary" [disabled]="!upcropUpload.uploader.queue.length" (click)="goToStep2()">Continuar</button>
</mat-dialog-actions>
<mat-dialog-actions *ngIf="steps.current.number == 2">
<button mat-button (click)="goToStep1()">Voltar</button>
<button mat-button color="primary" [fxHide]="upcropCrop.uploader?.queue?.length == (upcropCrop.currentNumber + 1)" (click)="upcropCrop.goToNextCrop()">Próxima imagem</button>
<button mat-button color="primary" [fxHide]="upcropCrop.uploader?.queue?.length > (upcropCrop.currentNumber + 1)" [disabled]="upcropCrop.uploading"
(click)="finish()">Concluir</button>
</mat-dialog-actions>
`,
styles: [`[mat-dialog-title] small{color:#b5b5b5!important;font:400 16px/28px Roboto,"Helvetica Neue",sans-serif!important;margin:0 0 16px!important}[steps]{margin:0 -24px 16px;padding-top:16px;padding-bottom:16px;background-color:rgba(0,0,0,.04)}[steps] .has-text-primary{color:#3f51b5!important}[mat-dialog-title] .has-text-danger{color:#f44336!important}`]
},] },
];
/** @nocollapse */
UpcropDialogComponent.ctorParameters = () => [
{ type: MatDialogRef },
{ type: undefined, decorators: [{ type: Inject, args: [MAT_DIALOG_DATA,] }] }
];
UpcropDialogComponent.propDecorators = {
upcropUpload: [{ type: ViewChild, args: ['upcropUpload',] }],
upcropCrop: [{ type: ViewChild, args: ['upcropCrop',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropService {
/**
* @param {?} dialog
*/
constructor(dialog) {
this.dialog = dialog;
this.dialogConfig = {
width: '80%'
};
this.uploadConfig = {
url: null,
authToken: null,
autoUpload: false,
additionalParameter: {},
withCredentials: false
};
this.cropConfig = {
movable: true,
scalable: true,
zoomable: true,
viewMode: 1,
autoCrop: true,
autoCropArea: 1
};
}
/**
* @param {?=} dialogConfig
* @param {?=} uploadConfig
* @param {?=} cropConfig
* @return {?}
*/
open(dialogConfig = this.dialogConfig, uploadConfig = this.uploadConfig, cropConfig = this.cropConfig) {
//
// Merge config
this.uploadConfig = Object.assign(this.uploadConfig, uploadConfig);
this.cropConfig = Object.assign(this.cropConfig, cropConfig);
this.dialogConfig = Object.assign({}, this.dialogConfig, dialogConfig, {
data: {
uploadConfig: this.uploadConfig,
cropConfig: this.cropConfig
}
});
//
// Create promise to return the dialog result
return new Promise((resolve, reject) => {
/** @type {?} */
let dialogRef = this.dialog.open(UpcropDialogComponent, this.dialogConfig);
//
// Subscribe to on close event
dialogRef.afterClosed().subscribe(result => {
//
// Validate result
if (result) {
resolve(result);
}
else {
reject();
}
});
});
}
}
UpcropService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
UpcropService.ctorParameters = () => [
{ type: MatDialog }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropComponent {
constructor() { }
/**
* @return {?}
*/
ngOnInit() {
}
}
UpcropComponent.decorators = [
{ type: Component, args: [{
selector: 'angular-upcrop',
template: `<p>
upcrop works!
</p>
`,
styles: [``]
},] },
];
/** @nocollapse */
UpcropComponent.ctorParameters = () => [];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class UpcropImagePreviewDirective {
/**
* @param {?} el
* @param {?} renderer
*/
constructor(el, renderer) {
this.el = el;
this.renderer = renderer;
}
/**
* Ng on changes
* Read file when image changes
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
/** @type {?} */
let reader = new FileReader();
/** @type {?} */
let el = this.el;
//
// On load
reader.onloadend = function (e) {
el.nativeElement.src = reader.result;
};
//
// Validate
if (this.image) {
return reader.readAsDataURL(this.image);
}
}
}
UpcropImagePreviewDirective.decorators = [
{ type: Directive, args: [{
selector: 'img[upcropImagePreview]'
},] },
];
/** @nocollapse */
UpcropImagePreviewDirective.ctorParameters = () => [
{ type: ElementRef },
{ type: Renderer2 }
];
UpcropImagePreviewDirective.propDecorators = {
image: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class AngularUpcropModule {
}
AngularUpcropModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
FileUploadModule,
FlexLayoutModule,
MatDialogModule,
MatIconModule,
MatButtonModule,
MatCardModule,
MatTooltipModule,
AngularCropperjsModule
],
declarations: [UpcropComponent, UpcropDialogComponent, UpcropCropComponent, UpcropUploadComponent, UpcropImagePreviewDirective],
exports: [UpcropComponent, UpcropDialogComponent, UpcropCropComponent, UpcropUploadComponent, UpcropImagePreviewDirective],
entryComponents: [UpcropDialogComponent]
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
export { UpcropService, UpcropComponent, UpcropDialogComponent, UpcropCropComponent, UpcropUploadComponent, UpcropImagePreviewDirective, AngularUpcropModule };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci11cGNyb3AuanMubWFwIiwic291cmNlcyI6WyJuZzovL2FuZ3VsYXItdXBjcm9wL2xpYi91cGNyb3AtdXBsb2FkL3VwY3JvcC11cGxvYWQuY29tcG9uZW50LnRzIiwibmc6Ly9hbmd1bGFyLXVwY3JvcC9saWIvdXBjcm9wLWNyb3AvdXBjcm9wLWNyb3AuY29tcG9uZW50LnRzIiwibmc6Ly9hbmd1bGFyLXVwY3JvcC9saWIvdXBjcm9wLWRpYWxvZy91cGNyb3AtZGlhbG9nLmNvbXBvbmVudC50cyIsIm5nOi8vYW5ndWxhci11cGNyb3AvbGliL3VwY3JvcC5zZXJ2aWNlLnRzIiwibmc6Ly9hbmd1bGFyLXVwY3JvcC9saWIvdXBjcm9wL3VwY3JvcC5jb21wb25lbnQudHMiLCJuZzovL2FuZ3VsYXItdXBjcm9wL2xpYi91cGNyb3AtaW1hZ2UtcHJldmlldy91cGNyb3AtaW1hZ2UtcHJldmlldy5kaXJlY3RpdmUudHMiLCJuZzovL2FuZ3VsYXItdXBjcm9wL2xpYi9hbmd1bGFyLXVwY3JvcC5tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRmlsZVVwbG9hZGVyLCBGaWxlSXRlbSwgUGFyc2VkUmVzcG9uc2VIZWFkZXJzIH0gZnJvbSAnbmcyLWZpbGUtdXBsb2FkJztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICd1cGNyb3AtdXBsb2FkJyxcbiAgICB0ZW1wbGF0ZTogYDxsYWJlbCBuZzJGaWxlRHJvcCBtdWx0aXBsZSBjbGFzcz1cIm15LWRyb3Atem9uZVwiIFtuZ0NsYXNzXT1cInsnbnYtZmlsZS1vdmVyJzogaGFzRmlsZU92ZXJ9XCIgKGZpbGVPdmVyKT1cIm9uRmlsZU92ZXIoJGV2ZW50KVwiXG4gICAgW3VwbG9hZGVyXT1cInVwbG9hZGVyXCIgZnhMYXlvdXQgZnhMYXlvdXRBbGlnbj1cImNlbnRlciBjZW50ZXJcIj5cbiAgICDDg8KBcmVhIGRlIHVwbG9hZFxuICAgIDxpbnB1dCB0eXBlPVwiZmlsZVwiIG5nMkZpbGVTZWxlY3QgbXVsdGlwbGUgW3VwbG9hZGVyXT1cInVwbG9hZGVyXCIgc3R5bGU9XCJkaXNwbGF5OiBub25lXCIgLz5cbjwvbGFiZWw+XG5cbjwhLS0gRklMRVMgLS0+XG48dGFibGUgY2xhc3M9XCJ0YWJsZSB1cGNyb3AtdXBsb2FkLXRhYmxlXCI+XG4gICAgPHRoZWFkPlxuICAgICAgICA8dHI+XG4gICAgICAgICAgICA8dGg+UHJldmlldzwvdGg+XG4gICAgICAgICAgICA8dGg+QXJxdWl2bzwvdGg+XG4gICAgICAgICAgICA8dGggc3R5bGU9XCJ3aWR0aDozMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXJcIj5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJpcy1wdWxsZWQtcmlnaHRcIj5zZXR0aW5nczwvbWF0LWljb24+XG4gICAgICAgICAgICA8L3RoPlxuICAgICAgICA8L3RyPlxuICAgIDwvdGhlYWQ+XG5cbiAgICA8dGJvZHk+XG4gICAgICAgIDx0ciAqbmdGb3I9XCJsZXQgaXRlbSBvZiB1cGxvYWRlci5xdWV1ZVwiPlxuICAgICAgICAgICAgPHRkIGNsYXNzPVwiaW1hZ2UtcHJldmlld1wiIHN0eWxlPVwid2lkdGg6MTAwcHhcIj5cbiAgICAgICAgICAgICAgICA8aW1nIHVwY3JvcEltYWdlUHJldmlldyBbaW1hZ2VdPVwiaXRlbT8uX2ZpbGVcIiBjbGFzcz1cIm1lZGlhLW9iamVjdFwiIC8+XG4gICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgPHRkPnt7IHRydW5jYXRlKGl0ZW0/LmZpbGU/Lm5hbWUsIDE2KSB9fTwvdGQ+XG4gICAgICAgICAgICA8dGQgY2xhc3M9XCJhY3Rpb25zXCIgc3R5bGU9XCJ3aWR0aDozMHB4XCI+XG4gICAgICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImRhbmdlci1idG5cIiBtYXQtaWNvbi1idXR0b24gY29sb3I9XCJ3YXJuXCIgKGNsaWNrKT1cIml0ZW0ucmVtb3ZlKClcIj5cbiAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L3RkPlxuICAgICAgICA8L3RyPlxuICAgICAgICA8dHIgW2hpZGRlbl09XCJ1cGxvYWRlci5xdWV1ZS5sZW5ndGhcIj5cbiAgICAgICAgICAgIDx0ZCBjb2xzcGFuPVwiM1wiIGNsYXNzPVwiaGFzLXRleHQtZGFuZ2VyXCI+XG4gICAgICAgICAgICAgICAgTmVuaHVtIGFycXVpdm8sIGFkaWNpb25lIGFjaW1hLlxuICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgPC90cj5cbiAgICA8L3Rib2R5PlxuPC90YWJsZT5cbmAsXG4gICAgc3R5bGVzOiBbYC5teS1kcm9wLXpvbmV7Ym9yZGVyOjJweCBkYXNoZWQgcmdiYSgwLDAsMCwuMDQpO3dpZHRoOjEwMCU7ZGlzcGxheTpmbGV4O3BhZGRpbmc6MjBweDtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwwLDAsLjA0KTtjb2xvcjpyZ2JhKDAsMCwwLC43KX0ubnYtZmlsZS1vdmVye2JvcmRlcjoycHggZGFzaGVkIHJnYmEoMjQ0LDY3LDU0LC40KX1bdXBjcm9wSW1hZ2VQcmV2aWV3XXtkaXNwbGF5OmJsb2NrfS51cGNyb3AtdXBsb2FkLXRhYmxle2JhY2tncm91bmQtY29sb3I6I2ZmZjtjb2xvcjojMzYzNjM2O2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTtib3JkZXItc3BhY2luZzowO3dpZHRoOjEwMCU7bWFyZ2luLWJvdHRvbTowfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoe2JvcmRlcjoxcHggc29saWQgI2RiZGJkYjtib3JkZXItd2lkdGg6MCAwIDFweDtwYWRkaW5nOi41ZW0gLjc1ZW07dmVydGljYWwtYWxpZ246dG9wfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLXdoaXRlLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLXdoaXRle2JhY2tncm91bmQtY29sb3I6I2ZmZjtib3JkZXItY29sb3I6I2ZmZjtjb2xvcjojMGEwYTBhfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLWJsYWNrLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLWJsYWNre2JhY2tncm91bmQtY29sb3I6IzBhMGEwYTtib3JkZXItY29sb3I6IzBhMGEwYTtjb2xvcjojZmZmfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLWxpZ2h0LC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLWxpZ2h0e2JhY2tncm91bmQtY29sb3I6I2Y1ZjVmNTtib3JkZXItY29sb3I6I2Y1ZjVmNTtjb2xvcjojMzYzNjM2fS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLWRhcmssLnVwY3JvcC11cGxvYWQtdGFibGUgdGguaXMtZGFya3tiYWNrZ3JvdW5kLWNvbG9yOiMzNjM2MzY7Ym9yZGVyLWNvbG9yOiMzNjM2MzY7Y29sb3I6I2Y1ZjVmNX0udXBjcm9wLXVwbG9hZC10YWJsZSB0ZC5pcy1wcmltYXJ5LC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLXByaW1hcnl7YmFja2dyb3VuZC1jb2xvcjojMDBkMWIyO2JvcmRlci1jb2xvcjojMDBkMWIyO2NvbG9yOiNmZmZ9LnVwY3JvcC11cGxvYWQtdGFibGUgdGQuaXMtaW5mbywudXBjcm9wLXVwbG9hZC10YWJsZSB0aC5pcy1pbmZve2JhY2tncm91bmQtY29sb3I6IzMyNzNkYztib3JkZXItY29sb3I6IzMyNzNkYztjb2xvcjojZmZmfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLXN1Y2Nlc3MsLnVwY3JvcC11cGxvYWQtdGFibGUgdGguaXMtc3VjY2Vzc3tiYWNrZ3JvdW5kLWNvbG9yOiMyM2QxNjA7Ym9yZGVyLWNvbG9yOiMyM2QxNjA7Y29sb3I6I2ZmZn0udXBjcm9wLXVwbG9hZC10YWJsZSB0ZC5pcy13YXJuaW5nLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLXdhcm5pbmd7YmFja2dyb3VuZC1jb2xvcjojZmZkZDU3O2JvcmRlci1jb2xvcjojZmZkZDU3O2NvbG9yOnJnYmEoMCwwLDAsLjcpfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkLmlzLWRhbmdlciwudXBjcm9wLXVwbG9hZC10YWJsZSB0aC5pcy1kYW5nZXJ7YmFja2dyb3VuZC1jb2xvcjojZmYzODYwO2JvcmRlci1jb2xvcjojZmYzODYwO2NvbG9yOiNmZmZ9LnVwY3JvcC11cGxvYWQtdGFibGUgdGQuaXMtbmFycm93LC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoLmlzLW5hcnJvd3t3aGl0ZS1zcGFjZTpub3dyYXA7d2lkdGg6MSV9LnVwY3JvcC11cGxvYWQtdGFibGUgdGh7Y29sb3I6IzM2MzYzNjt0ZXh0LWFsaWduOmxlZnR9LnVwY3JvcC11cGxvYWQtdGFibGUgdHI6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjojZmFmYWZhfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRyLmlzLXNlbGVjdGVke2JhY2tncm91bmQtY29sb3I6IzAwZDFiMjtjb2xvcjojZmZmfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRyLmlzLXNlbGVjdGVkIGEsLnVwY3JvcC11cGxvYWQtdGFibGUgdHIuaXMtc2VsZWN0ZWQgc3Ryb25ne2NvbG9yOmN1cnJlbnRDb2xvcn0udXBjcm9wLXVwbG9hZC10YWJsZSB0ci5pcy1zZWxlY3RlZCB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZSB0ci5pcy1zZWxlY3RlZCB0aHtib3JkZXItY29sb3I6I2ZmZjtjb2xvcjpjdXJyZW50Q29sb3J9LnVwY3JvcC11cGxvYWQtdGFibGUgdGZvb3QgdGQsLnVwY3JvcC11cGxvYWQtdGFibGUgdGZvb3QgdGh7Ym9yZGVyLXdpZHRoOjJweCAwIDA7Y29sb3I6IzM2MzYzNn0udXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0cjpsYXN0LWNoaWxkIHRkLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRib2R5IHRyOmxhc3QtY2hpbGQgdGh7Ym9yZGVyLWJvdHRvbS13aWR0aDowfS51cGNyb3AtdXBsb2FkLXRhYmxlLmlzLWJvcmRlcmVkIHRkLC51cGNyb3AtdXBsb2FkLXRhYmxlLmlzLWJvcmRlcmVkIHRoe2JvcmRlci13aWR0aDoxcHh9LnVwY3JvcC11cGxvYWQtdGFibGUuaXMtYm9yZGVyZWQgdHI6bGFzdC1jaGlsZCB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZS5pcy1ib3JkZXJlZCB0cjpsYXN0LWNoaWxkIHRoe2JvcmRlci1ib3R0b20td2lkdGg6MXB4fS51cGNyb3AtdXBsb2FkLXRhYmxlLmlzLWZ1bGx3aWR0aHt3aWR0aDoxMDAlfS51cGNyb3AtdXBsb2FkLXRhYmxlLmlzLW5hcnJvdyB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZS5pcy1uYXJyb3cgdGh7cGFkZGluZzouMjVlbSAuNWVtfS51cGNyb3AtdXBsb2FkLXRhYmxlLmlzLXN0cmlwZWQgdGJvZHkgdHI6bm90KC5pcy1zZWxlY3RlZCk6bnRoLWNoaWxkKGV2ZW4pe2JhY2tncm91bmQtY29sb3I6I2ZhZmFmYX0udXBjcm9wLXVwbG9hZC10YWJsZS5pcy1zdHJpcGVkIHRib2R5IHRyOm5vdCguaXMtc2VsZWN0ZWQpOm50aC1jaGlsZChldmVuKTpob3ZlcntiYWNrZ3JvdW5kLWNvbG9yOiNmNWY1ZjV9dGQsdGh7cGFkZGluZzowO3RleHQtYWxpZ246bGVmdH0udXBjcm9wLXVwbG9hZC10YWJsZS1zZWFyY2h7ZGlzcGxheTpmbGV4O3BhZGRpbmc6MS4zZW0gMS42ZW19LnVwY3JvcC11cGxvYWQtdGFibGUtc2VhcmNoIGlucHV0e2ZvbnQtc2l6ZToxNHB4O2ZsZXg6MSAxIDEwMCU7Ym94LXNpemluZzpib3JkZXItYm94Oy13ZWJraXQtYm94LWZsZXg6MTtib3JkZXI6bm9uZTtiYWNrZ3JvdW5kLWNvbG9yOnRyYW5zcGFyZW50O291dGxpbmU6LXdlYmtpdC1mb2N1cy1yaW5nLWNvbG9yIGF1dG8gMCFpbXBvcnRhbnR9LnVwY3JvcC11cGxvYWQtdGFibGUtc2VhcmNoPm1hdC1pY29ue21hcmdpbi1yaWdodDoxNnB4O21hcmdpbi10b3A6MnB4fVt0YWJsZS1sb2FkaW5nXXtwb3NpdGlvbjphYnNvbHV0ZTt3aWR0aDoxMDAlO21hcmdpbi10b3A6NTlweCFpbXBvcnRhbnQ7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDI1NSwyNTUsMjU1LC45KTtoZWlnaHQ6Y2FsYygxMDAlIC0gNTlweCk7ei1pbmRleDoxfVt0YWJsZS1uby1lbnRyaWVzXXtwYWRkaW5nOjEuNmVtfS5tYXQtY2FyZFtoYXMtdGFibGVde3BhZGRpbmc6MH0ubWF0LWNhcmRbaGFzLXRhYmxlXSAubWF0LWNhcmQtYWN0aW9uc3twYWRkaW5nOjhweCFpbXBvcnRhbnQ7bWFyZ2luOjA7Ym9yZGVyLXRvcDoxcHggc29saWQgI2RiZGJkYjtib3JkZXItY29sb3I6cmdiYSgwLDAsMCwuMDkpfS5tYXQtY2FyZFtoYXMtdGFibGVdIC5tYXQtY2FyZC1hY3Rpb25zIC5tYXQtaWNvbi1idXR0b257Y29sb3I6cmdiYSgwLDAsMCwuNTQpfS5tYXQtY2FyZFtoYXMtdGFibGVdIC5tYXQtY2FyZC1hY3Rpb25zIC5tYXQtaWNvbi1idXR0b25bZGlzYWJsZWRde2NvbG9yOnJnYmEoMCwwLDAsLjE4KX0ubWF0LWNhcmRbaGFzLXRhYmxlXSAubWF0LWNhcmQtYWN0aW9ucyAubWF0LXBhZ2luYXRvci1wYWdlLXNpemUtbGFiZWx7bWFyZ2luOjAgMTVweDtjb2xvcjpyZ2JhKDAsMCwwLC41NCk7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6NDAwfS51cGNyb3AtdXBsb2FkLXRhYmxlIC5hY3Rpb25zIC5tYXQtaWNvbi1idXR0b257aGVpZ2h0OjMwcHghaW1wb3J0YW50O3dpZHRoOjMwcHg7bGluZS1oZWlnaHQ6MzBweDtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Ym94LXNpemluZzpib3JkZXItYm94O2Rpc3BsYXk6ZmxleDttYXgtd2lkdGg6MTAwJTtwbGFjZS1jb250ZW50OmNlbnRlcjthbGlnbi1pdGVtczpjZW50ZXJ9LnVwY3JvcC11cGxvYWQtdGFibGUgLmFjdGlvbnMgLm1hdC1pY29uLWJ1dHRvbiAubWF0LWljb257Zm9udC1zaXplOjE4cHg7bGluZS1oZWlnaHQ6MThweDt3aWR0aDoxOHB4O2hlaWdodDoxOHB4fS51cGNyb3AtdXBsb2FkLXRhYmxlIHRoZWFkIHRye2JhY2tncm91bmQtY29sb3I6cmdiYSgwLDAsMCwuMDQpIWltcG9ydGFudH0udXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0ZDpmaXJzdC1vZi10eXBlLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRoZWFkIHRoOmZpcnN0LW9mLXR5cGV7cGFkZGluZy1sZWZ0OjEuOGVtfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRoZWFkIHRkOmxhc3Qtb2YtdHlwZSwudXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0aDpsYXN0LW9mLXR5cGV7cGFkZGluZy1yaWdodDoxLjhlbX0udXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0ZCBtYXQtaWNvbiwudXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0aCBtYXQtaWNvbntoZWlnaHQ6MTZweDt3aWR0aDoxNnB4O2xpbmUtaGVpZ2h0OjE2cHg7Zm9udC1zaXplOjE2cHg7dmVydGljYWwtYWxpZ246Ym90dG9tO21hcmdpbi1yaWdodDozcHh9LnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGQsLnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGh7Ym9yZGVyLWNvbG9yOnJnYmEoMCwwLDAsLjA0KX0udXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0ZDpmaXJzdC1vZi10eXBlLC51cGNyb3AtdXBsb2FkLXRhYmxlIHRib2R5IHRoOmZpcnN0LW9mLXR5cGV7cGFkZGluZy1sZWZ0OjEuNmVtfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRib2R5IHRkOmxhc3Qtb2YtdHlwZSwudXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0aDpsYXN0LW9mLXR5cGV7cGFkZGluZy1yaWdodDoxLjZlbX0udXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0aHtjb2xvcjpyZ2JhKDAsMCwwLC41NCk7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6NDAwO3BhZGRpbmc6MS4zZW0gLjc1ZW07Ym9yZGVyOjB9LnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGR7Y29sb3I6cmdiYSgwLDAsMCwuODcpO3BhZGRpbmc6MWVtIC43NWVtO2ZvbnQtc2l6ZTouOXJlbTtmb250LXdlaWdodDo0MDB9QG1lZGlhIChtYXgtd2lkdGg6ODAwcHgpey51cGNyb3AtdXBsb2FkLXRhYmxle2Rpc3BsYXk6aW5saW5lLWJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcDttYXgtd2lkdGg6MTAwJTtvdmVyZmxvdy14OmF1dG87d2hpdGUtc3BhY2U6bm93cmFwO2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTtib3JkZXItc3BhY2luZzowO2Rpc3BsYXk6ZmxleDtvdmVyZmxvdzpoaWRkZW47YmFja2dyb3VuZDowIDB9LnVwY3JvcC11cGxvYWQtdGFibGUgLmFjdGlvbnMgYXttYXJnaW4tdG9wOi0uMzVlbX0udXBjcm9wLXVwbG9hZC10YWJsZSAuaXMtcHVsbGVkLXJpZ2h0e2Zsb2F0Om5vbmUhaW1wb3J0YW50fS51cGNyb3AtdXBsb2FkLXRhYmxlIHRoZWFke2Rpc3BsYXk6ZmxleDtmbGV4LXNocmluazowO21pbi13aWR0aDotd2Via2l0LW1pbi1jb250ZW50O21pbi13aWR0aDotbW96LW1pbi1jb250ZW50O21pbi13aWR0aDptaW4tY29udGVudH0udXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0aHtwYWRkaW5nOjEuM2VtIDEuOGVtO3RleHQtYWxpZ246cmlnaHQ7d2lkdGg6MTAwJSFpbXBvcnRhbnR9LnVwY3JvcC11cGxvYWQtdGFibGUgdGhlYWQgdGQgbWF0LWljb24sLnVwY3JvcC11cGxvYWQtdGFibGUgdGhlYWQgdGggbWF0LWljb257bWFyZ2luLXJpZ2h0OjB9LnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHl7ZmxleDoxIDEgMTAwJTtib3gtc2l6aW5nOmJvcmRlci1ib3g7LXdlYmtpdC1ib3gtZmxleDoxOy13ZWJraXQtb3ZlcmZsb3ctc2Nyb2xsaW5nOnRvdWNoO2JhY2tncm91bmQ6cmFkaWFsLWdyYWRpZW50KGxlZnQsZWxsaXBzZSxyZ2JhKDAsMCwwLC4yKSAwLHRyYW5zcGFyZW50IDc1JSkgMCBjZW50ZXIscmFkaWFsLWdyYWRpZW50KHJpZ2h0LGVsbGlwc2UscmdiYSgwLDAsMCwuMikgMCx0cmFuc3BhcmVudCA3NSUpIDEwMCUgY2VudGVyO2JhY2tncm91bmQtc2l6ZToxMHB4IDEwMCUsMTBweCAxMDAlO2JhY2tncm91bmQtYXR0YWNobWVudDpzY3JvbGwsc2Nyb2xsO2JhY2tncm91bmQtcmVwZWF0Om5vLXJlcGVhdDtkaXNwbGF5OmZsZXg7cG9zaXRpb246cmVsYXRpdmU7b3ZlcmZsb3cteDphdXRvO292ZXJmbG93LXk6aGlkZGVuO21hcmdpbi1yaWdodDoxLjZlbX0udXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0cntmbGV4OjEgMSAxMDAlO2JveC1zaXppbmc6Ym9yZGVyLWJveDstd2Via2l0LWJveC1mbGV4OjF9LnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGQsLnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGh7cGFkZGluZzoxLjE1NWVtIDEuNmVtO3RleHQtYWxpZ246bGVmdCFpbXBvcnRhbnR9LnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGQ6Zmlyc3Qtb2YtdHlwZSwudXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0aDpmaXJzdC1vZi10eXBle3BhZGRpbmctbGVmdDoxLjZlbX0udXBjcm9wLXVwbG9hZC10YWJsZSB0Ym9keSB0ZDpsYXN0LW9mLXR5cGUsLnVwY3JvcC11cGxvYWQtdGFibGUgdGJvZHkgdGg6bGFzdC1vZi10eXBle3BhZGRpbmctcmlnaHQ6MS42ZW19LnVwY3JvcC11cGxvYWQtdGFibGUgdHJ7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjttaW4td2lkdGg6LXdlYmtpdC1taW4tY29udGVudDttaW4td2lkdGg6LW1vei1taW4tY29udGVudDttaW4td2lkdGg6bWluLWNvbnRlbnQ7ZmxleC1zaHJpbms6MH0udXBjcm9wLXVwbG9hZC10YWJsZSB0ZCwudXBjcm9wLXVwbG9hZC10YWJsZSB0aHtkaXNwbGF5OmJsb2NrO2JhY2tncm91bmQtaW1hZ2U6bm9uZSFpbXBvcnRhbnQ7Ym9yZGVyLWxlZnQ6MH0udXBjcm9wLXVwbG9hZC10YWJsZSB0ZDpmaXJzdC1jaGlsZCwudXBjcm9wLXVwbG9hZC10YWJsZSB0aDpmaXJzdC1jaGlsZHtiYWNrZ3JvdW5kLWltYWdlOmxpbmVhci1ncmFkaWVudCh0byByaWdodCwjZmZmIDUwJSxyZ2JhKDI1NSwyNTUsMjU1LDApIDEwMCUpO2JhY2tncm91bmQtcmVwZWF0Om5vLXJlcGVhdDtiYWNrZ3JvdW5kLXNpemU6MjBweCAxMDAlfS51cGNyb3AtdXBsb2FkLXRhYmxlIHRkOmxhc3QtY2hpbGQsLnVwY3JvcC11cGxvYWQtdGFibGUgdGg6bGFzdC1jaGlsZHtiYWNrZ3JvdW5kLWltYWdlOmxpbmVhci1ncmFkaWVudCh0byBsZWZ0LCNmZmYgNTAlLHJnYmEoMjU1LDI1NSwyNTUsMCkgMTAwJSk7YmFja2dyb3VuZC1yZXBlYXQ6bm8tcmVwZWF0O2JhY2tncm91bmQtcG9zaXRpb246MTAwJSAwO2JhY2tncm91bmQtc2l6ZToyMHB4IDEwMCV9LnVwY3JvcC11cGxvYWQtdGFibGUgdGQ6bm90KDpsYXN0LWNoaWxkKSwudXBjcm9wLXVwbG9hZC10YWJsZSB0aDpub3QoOmxhc3QtY2hpbGQpe2JvcmRlci1ib3R0b206MH19LnVwY3JvcC11cGxvYWQtdGFibGUgOjotd2Via2l0LXNjcm9sbGJhcntoZWlnaHQ6OHB4O292ZXJmbG93OnZpc2libGU7d2lkdGg6MTZweH0udXBjcm9wLXVwbG9hZC10YWJsZSA6Oi13ZWJraXQtc2Nyb2xsYmFyLWJ1dHRvbntoZWlnaHQ6MDt3aWR0aDowfS51cGNyb3AtdXBsb2FkLXRhYmxlIDo6LXdlYmtpdC1zY3JvbGxiYXItY29ybmVye2JhY2tncm91bmQ6MCAwfS51cGNyb3AtdXBsb2FkLXRhYmxlIDo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWJ7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsMCwwLC4yKTtiYWNrZ3JvdW5kLWNsaXA6cGFkZGluZy1ib3g7Ym9yZGVyOnNvbGlkIHRyYW5zcGFyZW50O2JvcmRlci13aWR0aDoxcHggMXB4IDFweCA2cHg7bWluLWhlaWdodDoyOHB4O3BhZGRpbmc6MTAwcHggMCAwO2JveC1zaGFkb3c6aW5zZXQgMXB4IDFweCAwIHJnYmEoMCwwLDAsLjEpLGluc2V0IDAgLTFweCAwIHJnYmEoMCwwLDAsLjA3KX0udXBjcm9wLXVwbG9hZC10YWJsZSA6Oi13ZWJraXQtc2Nyb2xsYmFyLXRyYWNre2JhY2tncm91bmQtY2xpcDpwYWRkaW5nLWJveDtib3JkZXI6c29saWQgdHJhbnNwYXJlbnQ7Ym9yZGVyLXdpZHRoOjAgMCAwIDRweH1bZW50ZXJsaXN0XSBbaGFzLXRhYmxlXXttYXJnaW4tcmlnaHQ6LTI0cHg7bWFyZ2luLWxlZnQ6LTI0cHh9W2VudGVybGlzdF0gW2hhcy10YWJsZV0gLnVwY3JvcC11cGxvYWQtdGFibGV7YmFja2dyb3VuZC1jb2xvcjp0cmFuc3BhcmVudH1bZW50ZXJsaXN0XSBbaGFzLXRhYmxlXSAudXBjcm9wLXVwbG9hZC10YWJsZSB0aGVhZCB0cntiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwwLDAsLjAyKSFpbXBvcnRhbnR9W2VudGVybGlzdF0gW2hhcy10YWJsZV0gLnVwY3JvcC11cGxvYWQtdGFibGUgdHI6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjppbmhlcml0fS5pbWFnZS1wcmV2aWV3IGltZ3ttYXgtd2lkdGg6MTAwJX1gXVxufSlcbmV4cG9ydCBjbGFzcyBVcGNyb3BVcGxvYWRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gICAgQElucHV0KCkgcHVibGljIGNvbmZpZzogYW55ID0ge307XG4gICAgQElucHV0KCkgcHVibGljIHVwbG9hZFF1ZXVlOiBhbnkgPSBbXTtcbiAgICBAT3V0cHV0KCkgcHVibGljIG9uVXBsb2FkUXVldWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgQE91dHB1dCgpIHB1YmxpYyBvblVwbG9hZEltYWdlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgcHVibGljIHVwbG9hZGVyOiBGaWxlVXBsb2FkZXIgPSBuZXcgRmlsZVVwbG9hZGVyKHt9KTtcbiAgICBwdWJsaWMgaGFzRmlsZU92ZXI6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKCkgeyB9XG5cbiAgICBuZ09uSW5pdCgpIHtcblxuICAgICAgICAvL1xuICAgICAgICAvLyBTZXQgdXBsb2FkZXJcbiAgICAgICAgdGhpcy5zZXRVcGxvYWRlcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cGxvYWRlclxuICAgICAqL1xuICAgIHNldFVwbG9hZGVyKCkge1xuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIENvbnRleHQgZm9yIHVwbG9hZGVyXG4gICAgICAgIGxldCBzZWxmID0gdGhpcztcblxuICAgICAgICAvL1xuICAgICAgICAvLyBTZXQgdXBsb2FkZXJcbiAgICAgICAgdGhpcy51cGxvYWRlci5zZXRPcHRpb25zKHsgdXJsOiB0aGlzLmNvbmZpZy51cmwsIGF1dGhUb2tlbjogdGhpcy5jb25maWcuYXV0aFRva2VuLCBhdXRvVXBsb2FkOiB0aGlzLmNvbmZpZy5hdXRvVXBsb2FkLCBhZGRpdGlvbmFsUGFyYW1ldGVyOiB0aGlzLmNvbmZpZy5hZGRpdGlvbmFsUGFyYW1ldGVyIH0pO1xuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIEFmdGVyIGFkZCBmaWxlIGV2ZW50XG4gICAgICAgIHRoaXMudXBsb2FkZXIub25BZnRlckFkZGluZ0ZpbGUgPSAoZmlsZSkgPT4ge1xuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gU2V0IHdpdGggY3JlZGVudGlhbHNcbiAgICAgICAgICAgIGZpbGUud2l0aENyZWRlbnRpYWxzID0gdGhpcy5jb25maWcud2l0aENyZWRlbnRpYWxzO1xuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gRW1pdCBvblVwbG9hZFF1ZXVlXG4gICAgICAgICAgICB0aGlzLm9uVXBsb2FkUXVldWUuZW1pdCh7XG4gICAgICAgICAgICAgICAgZmlsZTogZmlsZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gT24gc3VjY2VzcyBpdGVtIGV2ZW50XG4gICAgICAgIHRoaXMudXBsb2FkZXIub25TdWNjZXNzSXRlbSA9IChpdGVtOiBGaWxlSXRlbSwgcmVzcG9uc2U6IHN0cmluZywgc3RhdHVzOiBudW1iZXIsIGhlYWRlcnM6IFBhcnNlZFJlc3BvbnNlSGVhZGVycykgPT4ge1xuXG4gICAgICAgICAgICBpZiAoc3RhdHVzID09IDIwMCkge1xuXG4gICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAvLyBQYXJzZSByZXNwb25zZVxuICAgICAgICAgICAgICAgIGxldCBkYXRhID0gSlNPTi5wYXJzZShyZXNwb25zZSk7XG5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIEVtaXQgb25VcGxvYWRRdWV1ZVxuICAgICAgICAgICAgICAgIHRoaXMub25VcGxvYWRJbWFnZS5lbWl0KHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogZGF0YVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBmaWxlIG92ZXIgZXZlbnRcbiAgICAgKiBAcGFyYW0gZVxuICAgICAqL1xuICAgIHB1YmxpYyBvbkZpbGVPdmVyKGU6IGFueSk6IHZvaWQge1xuICAgICAgICB0aGlzLmhhc0ZpbGVPdmVyID0gZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcnVuY2F0ZSBmaWxlbmF