diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..76ad5eb --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,31 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ dev ] + pull_request: + branches: [ dev ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x, 14.x, 16.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run build --if-present + - run: npm test diff --git a/angular.json b/angular.json index 735e935..bf588f8 100644 --- a/angular.json +++ b/angular.json @@ -66,7 +66,8 @@ "src/main/webapp/content/js/paper-dashboard.js", "src/main/webapp/content/js/perfect-scrollbar.min.js", "src/main/webapp/content/js/sweetalert2.js", - "./node_modules/swiper/swiper-bundle.min.js" + "./node_modules/swiper/swiper-bundle.min.js", + "src/main/webapp/content/js/api-google-platform.js" ] }, "configurations": { diff --git a/package-lock.json b/package-lock.json index 250092c..24ede43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,8 @@ "@ng-bootstrap/ng-bootstrap": "9.1.3", "@ngx-translate/core": "13.0.0", "@ngx-translate/http-loader": "6.0.0", + "@types/gapi.auth2": "0.0.54", + "angularx-social-login": "^4.0.1", "bootstrap": "4.6.0", "dayjs": "1.10.5", "ngx-infinite-scroll": "10.0.1", @@ -4227,6 +4229,19 @@ "@types/node": "*" } }, + "node_modules/@types/gapi": { + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@types/gapi/-/gapi-0.0.40.tgz", + "integrity": "sha512-HzV7JIp5vgCZYPLzTg+LJCEVbTbZ/wNSCatNYThNvDTtiNXU+ccrUfFLUF2akHsil+KCpf2yp9OUhLUflsOuBw==" + }, + "node_modules/@types/gapi.auth2": { + "version": "0.0.54", + "resolved": "https://registry.npmjs.org/@types/gapi.auth2/-/gapi.auth2-0.0.54.tgz", + "integrity": "sha512-4HEphaKsGndb9+tnd2PBBmxloaij04iYXVsjgHpFxqbPFt5Le6pasoh5g5BEtwp/YEm9xDbzssp44BYR2/7RcQ==", + "dependencies": { + "@types/gapi": "*" + } + }, "node_modules/@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -5091,6 +5106,18 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "node_modules/angularx-social-login": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/angularx-social-login/-/angularx-social-login-4.0.1.tgz", + "integrity": "sha512-dL65y0HXlKd8hhuH70/FFTxWsndEBU5DX2I1x7AcJ1ZAYpU6LPtQMbnzy10eSOcWZNeZX8XzaRaIbc4P+GjmvA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^12.0.0", + "@angular/core": "^12.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -30320,6 +30347,19 @@ "@types/node": "*" } }, + "@types/gapi": { + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@types/gapi/-/gapi-0.0.40.tgz", + "integrity": "sha512-HzV7JIp5vgCZYPLzTg+LJCEVbTbZ/wNSCatNYThNvDTtiNXU+ccrUfFLUF2akHsil+KCpf2yp9OUhLUflsOuBw==" + }, + "@types/gapi.auth2": { + "version": "0.0.54", + "resolved": "https://registry.npmjs.org/@types/gapi.auth2/-/gapi.auth2-0.0.54.tgz", + "integrity": "sha512-4HEphaKsGndb9+tnd2PBBmxloaij04iYXVsjgHpFxqbPFt5Le6pasoh5g5BEtwp/YEm9xDbzssp44BYR2/7RcQ==", + "requires": { + "@types/gapi": "*" + } + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -30984,6 +31024,14 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "angularx-social-login": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/angularx-social-login/-/angularx-social-login-4.0.1.tgz", + "integrity": "sha512-dL65y0HXlKd8hhuH70/FFTxWsndEBU5DX2I1x7AcJ1ZAYpU6LPtQMbnzy10eSOcWZNeZX8XzaRaIbc4P+GjmvA==", + "requires": { + "tslib": "^2.0.0" + } + }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", diff --git a/package.json b/package.json index 8cb4b47..b6ca8a7 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,8 @@ "@ng-bootstrap/ng-bootstrap": "9.1.3", "@ngx-translate/core": "13.0.0", "@ngx-translate/http-loader": "6.0.0", + "@types/gapi.auth2": "0.0.54", + "angularx-social-login": "^4.0.1", "bootstrap": "4.6.0", "dayjs": "1.10.5", "ngx-infinite-scroll": "10.0.1", diff --git a/src/main/java/org/datasurvey/config/ApplicationProperties.java b/src/main/java/org/datasurvey/config/ApplicationProperties.java index 86c8468..2481b0f 100644 --- a/src/main/java/org/datasurvey/config/ApplicationProperties.java +++ b/src/main/java/org/datasurvey/config/ApplicationProperties.java @@ -8,5 +8,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Properties are configured in the {@code application.yml} file. * See {@link tech.jhipster.config.JHipsterProperties} for a good example. */ + @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) public class ApplicationProperties {} diff --git a/src/main/java/org/datasurvey/config/SecurityConfiguration.java b/src/main/java/org/datasurvey/config/SecurityConfiguration.java index 1661950..f2e6e1b 100644 --- a/src/main/java/org/datasurvey/config/SecurityConfiguration.java +++ b/src/main/java/org/datasurvey/config/SecurityConfiguration.java @@ -92,6 +92,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .antMatchers("/api/account/reset-password/finish").permitAll() .antMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN) .antMatchers("/api/**").authenticated() + .antMatchers("/api/**").permitAll() .antMatchers("/websocket/**").authenticated() .antMatchers("/management/health").permitAll() .antMatchers("/management/health/**").permitAll() diff --git a/src/main/java/org/datasurvey/service/UserService.java b/src/main/java/org/datasurvey/service/UserService.java index e1d8bb5..227c590 100644 --- a/src/main/java/org/datasurvey/service/UserService.java +++ b/src/main/java/org/datasurvey/service/UserService.java @@ -156,7 +156,7 @@ public class UserService { * Modified to register extra user data * name, iconoPerfil, fechaNacimiento, estado, pais */ - public User registerUser(AdminUserDTO userDTO, String password, String name, Integer profileIcon, Integer isAdmin) { + public User registerUser(AdminUserDTO userDTO, String password, String name, Integer profileIcon, Integer isAdmin, Integer isGoogle) { userRepository .findOneByLogin(userDTO.getLogin().toLowerCase()) .ifPresent( @@ -190,7 +190,13 @@ public class UserService { newUser.setImageUrl(userDTO.getImageUrl()); newUser.setLangKey(userDTO.getLangKey()); // new user is not active - newUser.setActivated(false); + + if (isGoogle == 1) { + newUser.setActivated(true); + } else { + newUser.setActivated(false); + } + // new user gets registration key newUser.setActivationKey(RandomUtil.generateActivationKey()); Set authorities = new HashSet<>(); diff --git a/src/main/java/org/datasurvey/web/rest/AccountResource.java b/src/main/java/org/datasurvey/web/rest/AccountResource.java index 493ece3..afb4a0c 100644 --- a/src/main/java/org/datasurvey/web/rest/AccountResource.java +++ b/src/main/java/org/datasurvey/web/rest/AccountResource.java @@ -67,9 +67,13 @@ public class AccountResource { managedUserVM.getPassword(), managedUserVM.getName(), managedUserVM.getProfileIcon(), - managedUserVM.getIsAdmin() + managedUserVM.getIsAdmin(), + managedUserVM.getIsGoogle() ); - mailService.sendActivationEmail(user); + + if (managedUserVM.getIsGoogle() != 1) { + mailService.sendActivationEmail(user); + } } /** diff --git a/src/main/java/org/datasurvey/web/rest/vm/ManagedUserVM.java b/src/main/java/org/datasurvey/web/rest/vm/ManagedUserVM.java index 3d1dc73..5cc7a2b 100644 --- a/src/main/java/org/datasurvey/web/rest/vm/ManagedUserVM.java +++ b/src/main/java/org/datasurvey/web/rest/vm/ManagedUserVM.java @@ -24,6 +24,8 @@ public class ManagedUserVM extends AdminUserDTO { private Integer isAdmin; + private Integer isGoogle; + public ManagedUserVM() { // Empty constructor needed for Jackson. } @@ -60,6 +62,14 @@ public class ManagedUserVM extends AdminUserDTO { this.isAdmin = isAdmin; } + public Integer getIsGoogle() { + return isGoogle; + } + + public void setIsGoogle(Integer isGoogle) { + this.isGoogle = isGoogle; + } + // prettier-ignore @Override public String toString() { diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index c13b842..6f67fa6 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -95,7 +95,7 @@ jhipster: token-validity-in-seconds: 86400 token-validity-in-seconds-for-remember-me: 2592000 mail: # specific JHipster mail property, for standard properties see MailProperties - base-url: http://127.0.0.1:8080 + base-url: http://localhost:9000 logging: use-json-format: false # By default, logs are not in Json format logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration diff --git a/src/main/webapp/app/account/register/register.component.html b/src/main/webapp/app/account/register/register.component.html index dc27302..bd4e919 100644 --- a/src/main/webapp/app/account/register/register.component.html +++ b/src/main/webapp/app/account/register/register.component.html @@ -23,6 +23,10 @@ Registration failed! Please try again later. +
+ Login name already registered! Please choose another one. +
+
Email is already in use! Please choose another one.
@@ -34,7 +38,7 @@
- + Your email cannot be longer than 100 characters. + + + Se requiere un correo electrónico válido. +
- +
- + diff --git a/src/main/webapp/app/account/register/register.component.spec.ts b/src/main/webapp/app/account/register/register.component.spec.ts index 422a382..d040495 100644 --- a/src/main/webapp/app/account/register/register.component.spec.ts +++ b/src/main/webapp/app/account/register/register.component.spec.ts @@ -65,6 +65,7 @@ describe('Component Tests', () => { name: '', profileIcon: 1, isAdmin: 0, + isGoogle: 0, }); expect(comp.success).toBe(true); expect(comp.errorUserExists).toBe(false); diff --git a/src/main/webapp/app/account/register/register.component.ts b/src/main/webapp/app/account/register/register.component.ts index 24a7542..ddcc966 100644 --- a/src/main/webapp/app/account/register/register.component.ts +++ b/src/main/webapp/app/account/register/register.component.ts @@ -59,8 +59,8 @@ export class RegisterComponent implements AfterViewInit { registerForm = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(254)]], email: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], - password: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(50)]], - confirmPassword: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(50)]], + password: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(50)]], + confirmPassword: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(50)]], }); constructor(private translateService: TranslateService, private registerService: RegisterService, private fb: FormBuilder) {} @@ -84,7 +84,6 @@ export class RegisterComponent implements AfterViewInit { const login = this.registerForm.get(['email'])!.value; const email = this.registerForm.get(['email'])!.value; const name = this.registerForm.get(['name'])!.value; - console.log(name); this.registerService .save({ @@ -95,6 +94,7 @@ export class RegisterComponent implements AfterViewInit { name, profileIcon: this.profileIcon, isAdmin: 0, + isGoogle: 0, }) .subscribe( () => (this.success = true), @@ -103,7 +103,7 @@ export class RegisterComponent implements AfterViewInit { } } - private processError(response: HttpErrorResponse): void { + processError(response: HttpErrorResponse): void { if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) { this.errorUserExists = true; } else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) { diff --git a/src/main/webapp/app/account/register/register.model.ts b/src/main/webapp/app/account/register/register.model.ts index 3a3a97d..18a4688 100644 --- a/src/main/webapp/app/account/register/register.model.ts +++ b/src/main/webapp/app/account/register/register.model.ts @@ -6,6 +6,7 @@ export class Registration { public langKey: string, public name: string, public profileIcon: number, - public isAdmin: number + public isAdmin: number, + public isGoogle: number ) {} } diff --git a/src/main/webapp/app/account/settings/settings.component.ts b/src/main/webapp/app/account/settings/settings.component.ts index ef61479..f79e938 100644 --- a/src/main/webapp/app/account/settings/settings.component.ts +++ b/src/main/webapp/app/account/settings/settings.component.ts @@ -179,7 +179,6 @@ export class SettingsComponent implements OnInit { icon.class = 'active'; } }); - console.log(this.profileIcons); this.usersSharedCollection = this.userService.addUserToCollectionIfMissing(this.usersSharedCollection, usuarioExtra.user); this.plantillasSharedCollection = this.plantillaService.addPlantillaToCollectionIfMissing( diff --git a/src/main/webapp/app/app.module.ts b/src/main/webapp/app/app.module.ts index c297822..df110cd 100644 --- a/src/main/webapp/app/app.module.ts +++ b/src/main/webapp/app/app.module.ts @@ -17,6 +17,10 @@ import { SharedModule } from 'app/shared/shared.module'; import { AppRoutingModule } from './app-routing.module'; import { HomeModule } from './home/home.module'; import { EntityRoutingModule } from './entities/entity-routing.module'; +import { ReactiveFormsModule } from '@angular/forms'; + +import { SocialLoginModule, SocialAuthServiceConfig } from 'angularx-social-login'; +import { GoogleLoginProvider } from 'angularx-social-login'; // jhipster-needle-angular-add-module-import JHipster will add new module here import { NgbDateDayjsAdapter } from './config/datepicker-adapter'; import { fontAwesomeIcons } from './config/font-awesome-icons'; @@ -37,6 +41,7 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component'; // jhipster-needle-angular-add-module JHipster will add new module here EntityRoutingModule, AppRoutingModule, + SocialLoginModule, // Set this to true to enable service worker (PWA) ServiceWorkerModule.register('ngsw-worker.js', { enabled: false }), HttpClientModule, @@ -58,6 +63,18 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component'; { provide: LOCALE_ID, useValue: 'es' }, { provide: NgbDateAdapter, useClass: NgbDateDayjsAdapter }, httpInterceptorProviders, + { + provide: 'SocialAuthServiceConfig', + useValue: { + autoLogin: false, + providers: [ + { + id: GoogleLoginProvider.PROVIDER_ID, + provider: new GoogleLoginProvider('178178891217-b517thad8f15d4at2vk2410v7a09dcvt.apps.googleusercontent.com'), + }, + ], + } as SocialAuthServiceConfig, + }, ], declarations: [MainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, FooterComponent, SidebarComponent], bootstrap: [MainComponent], diff --git a/src/main/webapp/app/core/auth/auth-jwt.service.ts b/src/main/webapp/app/core/auth/auth-jwt.service.ts index 2316a18..6540a1e 100644 --- a/src/main/webapp/app/core/auth/auth-jwt.service.ts +++ b/src/main/webapp/app/core/auth/auth-jwt.service.ts @@ -36,6 +36,7 @@ export class AuthServerProvider { return new Observable(observer => { this.localStorageService.clear('authenticationToken'); this.sessionStorageService.clear('authenticationToken'); + this.localStorageService.clear('IsGoogle'); observer.complete(); }); } diff --git a/src/main/webapp/app/entities/categoria/delete/categoria-delete-dialog.component.html b/src/main/webapp/app/entities/categoria/delete/categoria-delete-dialog.component.html index ed57d17..3fae047 100644 --- a/src/main/webapp/app/entities/categoria/delete/categoria-delete-dialog.component.html +++ b/src/main/webapp/app/entities/categoria/delete/categoria-delete-dialog.component.html @@ -1,8 +1,8 @@ - + diff --git a/src/main/webapp/app/entities/categoria/detail/categoria-detail.component.html b/src/main/webapp/app/entities/categoria/detail/categoria-detail.component.html index fe0ee96..9531c6c 100644 --- a/src/main/webapp/app/entities/categoria/detail/categoria-detail.component.html +++ b/src/main/webapp/app/entities/categoria/detail/categoria-detail.component.html @@ -24,11 +24,11 @@ - -
diff --git a/src/main/webapp/app/entities/categoria/list/categoria.component.html b/src/main/webapp/app/entities/categoria/list/categoria.component.html index a6ef61e..7933f24 100644 --- a/src/main/webapp/app/entities/categoria/list/categoria.component.html +++ b/src/main/webapp/app/entities/categoria/list/categoria.component.html @@ -3,15 +3,10 @@ Categorias
- -
+ +
+
+ +
+ - - - +
ID Nombre Estado
- {{ categoria.id }} -
{{ categoria.nombre }} {{ categoria.estado }}
- - - diff --git a/src/main/webapp/app/entities/categoria/list/categoria.component.ts b/src/main/webapp/app/entities/categoria/list/categoria.component.ts index cb48c91..d0a9206 100644 --- a/src/main/webapp/app/entities/categoria/list/categoria.component.ts +++ b/src/main/webapp/app/entities/categoria/list/categoria.component.ts @@ -13,8 +13,11 @@ import { CategoriaDeleteDialogComponent } from '../delete/categoria-delete-dialo export class CategoriaComponent implements OnInit { categorias?: ICategoria[]; isLoading = false; + public searchString: string; - constructor(protected categoriaService: CategoriaService, protected modalService: NgbModal) {} + constructor(protected categoriaService: CategoriaService, protected modalService: NgbModal) { + this.searchString = ''; + } loadAll(): void { this.isLoading = true; @@ -31,6 +34,7 @@ export class CategoriaComponent implements OnInit { } ngOnInit(): void { + this.searchString = ''; this.loadAll(); } diff --git a/src/main/webapp/app/entities/categoria/update/categoria-update.component.html b/src/main/webapp/app/entities/categoria/update/categoria-update.component.html index 01dea01..289ccb3 100644 --- a/src/main/webapp/app/entities/categoria/update/categoria-update.component.html +++ b/src/main/webapp/app/entities/categoria/update/categoria-update.component.html @@ -1,12 +1,15 @@
-
+

- Create or edit a Categoria + Create or edit a Category

+
+ A category with that name already exists. +
@@ -39,7 +42,13 @@
- @@ -48,7 +57,7 @@ id="save-entity" data-cy="entityCreateSaveButton" [disabled]="editForm.invalid || isSaving" - class="btn btn-primary" + class="btn btn-primary ds-btn ds-btn-primary" >  Save diff --git a/src/main/webapp/app/entities/categoria/update/categoria-update.component.ts b/src/main/webapp/app/entities/categoria/update/categoria-update.component.ts index b5d24ae..29f8252 100644 --- a/src/main/webapp/app/entities/categoria/update/categoria-update.component.ts +++ b/src/main/webapp/app/entities/categoria/update/categoria-update.component.ts @@ -14,19 +14,32 @@ import { CategoriaService } from '../service/categoria.service'; }) export class CategoriaUpdateComponent implements OnInit { isSaving = false; + public categorias?: ICategoria[]; editForm = this.fb.group({ id: [], nombre: [null, [Validators.required]], estado: [null, [Validators.required]], }); + public duplicateName: boolean; - constructor(protected categoriaService: CategoriaService, protected activatedRoute: ActivatedRoute, protected fb: FormBuilder) {} + constructor(protected categoriaService: CategoriaService, protected activatedRoute: ActivatedRoute, protected fb: FormBuilder) { + this.duplicateName = false; + this.categorias = []; + this.loadAll(); + } ngOnInit(): void { this.activatedRoute.data.subscribe(({ categoria }) => { this.updateForm(categoria); }); + this.loadAll(); + } + + loadAll(): void { + this.categoriaService.query().subscribe(res => { + this.categorias = res.body ?? []; + }); } previousState(): void { @@ -36,13 +49,25 @@ export class CategoriaUpdateComponent implements OnInit { save(): void { this.isSaving = true; const categoria = this.createFromForm(); - if (categoria.id !== undefined) { - this.subscribeToSaveResponse(this.categoriaService.update(categoria)); + const condicion = this.categoryExists(categoria); + if (!condicion) { + if (categoria.id !== undefined) { + this.subscribeToSaveResponse(this.categoriaService.update(categoria)); + } else { + this.subscribeToSaveResponse(this.categoriaService.create(categoria)); + } } else { - this.subscribeToSaveResponse(this.categoriaService.create(categoria)); + this.duplicateName = true; + this.isSaving = false; } } + protected categoryExists(categoria: ICategoria): boolean { + this.loadAll(); + var condicion = this.categorias!.some(cat => cat.nombre!.toLowerCase() === categoria.nombre!.toLowerCase()); + return condicion; + } + protected subscribeToSaveResponse(result: Observable>): void { result.pipe(finalize(() => this.onSaveFinalize())).subscribe( () => this.onSaveSuccess(), diff --git a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.html b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.html index 95b20ad..a4ce1c6 100644 --- a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.html +++ b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.html @@ -1,21 +1,11 @@

- Usuario Extras + Usuarios
- - -

@@ -32,10 +22,10 @@ - - + + - + @@ -62,19 +52,19 @@ >{{ last ? '' : ', ' }} --> -
RolIcono PerfilRolIcono Nombre UsuarioCorreo electrónicoCorreo electrónico Estado +
- - diff --git a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.scss b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.scss index 8c65d1f..85a5c1e 100644 --- a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.scss +++ b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.scss @@ -10,3 +10,7 @@ list-style: none; padding-left: 10px; } + +.btn-group button { + margin: 0 2px; +} diff --git a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.ts b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.ts index c334029..1545b0b 100644 --- a/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.ts +++ b/src/main/webapp/app/entities/usuario-extra/list/usuario-extra.component.ts @@ -29,9 +29,9 @@ export class UsuarioExtraComponent implements OnInit { rolList = user.authorities; let a = rolList?.pop(); if (a == 'ROLE_ADMIN') { - user.authorities = ['ADMIN']; + user.authorities = ['Admin']; } else if (a == 'ROLE_USER') { - user.authorities = ['USUARIO']; + user.authorities = ['Usuario']; } }); this.publicUsers = res; diff --git a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.html b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.html index 1f2f81e..a56a4be 100644 --- a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.html +++ b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.html @@ -9,12 +9,12 @@

- REGISTRAR ADMIN + REGISTRAR ADMINISTRADOR

Ingrese los datos para registrar a un admin.

-
+
Registration saved! Please check your email for confirmation.
@@ -22,6 +22,10 @@ Registration failed! Please try again later.
+
+ Login name already registered! Please choose another one. +
+
Email is already in use! Please choose another one.
@@ -30,16 +34,24 @@ The password and its confirmation do not match!
- +
- + @@ -82,13 +94,13 @@
- + @@ -125,13 +137,17 @@ > Your email cannot be longer than 100 characters. + + + Se requiere un correo electrónico válido. +
- +
- + diff --git a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.spec.ts b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.spec.ts index c2e698a..2382221 100644 --- a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.spec.ts +++ b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.spec.ts @@ -65,6 +65,7 @@ describe('Component Tests', () => { name: '', profileIcon: 1, isAdmin: 1, + isGoogle: 0, }); expect(comp.success).toBe(true); expect(comp.errorUserExists).toBe(false); diff --git a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.ts b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.ts index f712e2b..aba080d 100644 --- a/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.ts +++ b/src/main/webapp/app/entities/usuario-extra/update/usuario-extra-update.component.ts @@ -57,8 +57,8 @@ export class UsuarioExtraUpdateComponent { registerForm = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(254)]], email: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], - password: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(50)]], - confirmPassword: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(50)]], + password: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(50)]], + confirmPassword: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(50)]], }); constructor(private translateService: TranslateService, private registerService: RegisterService, private fb: FormBuilder) {} @@ -82,7 +82,6 @@ export class UsuarioExtraUpdateComponent { const login = this.registerForm.get(['email'])!.value; const email = this.registerForm.get(['email'])!.value; const name = this.registerForm.get(['name'])!.value; - console.log(name); this.registerService .save({ @@ -93,6 +92,7 @@ export class UsuarioExtraUpdateComponent { name, profileIcon: this.profileIcon, isAdmin: 1, + isGoogle: 0, }) .subscribe( () => (this.success = true), diff --git a/src/main/webapp/app/layouts/sidebar/sidebar.component.html b/src/main/webapp/app/layouts/sidebar/sidebar.component.html index 9bd3d74..0c862fa 100644 --- a/src/main/webapp/app/layouts/sidebar/sidebar.component.html +++ b/src/main/webapp/app/layouts/sidebar/sidebar.component.html @@ -77,7 +77,7 @@
  • -

    Cerrar Sesion

    +

    Cerrar Sesión

  • diff --git a/src/main/webapp/app/layouts/sidebar/sidebar.component.ts b/src/main/webapp/app/layouts/sidebar/sidebar.component.ts index 1e5f057..75fc8f2 100644 --- a/src/main/webapp/app/layouts/sidebar/sidebar.component.ts +++ b/src/main/webapp/app/layouts/sidebar/sidebar.component.ts @@ -6,7 +6,7 @@ import { Account } from 'app/core/auth/account.model'; import { AccountService } from 'app/core/auth/account.service'; import { LoginService } from 'app/login/login.service'; import { ProfileService } from 'app/layouts/profiles/profile.service'; -import { SessionStorageService } from 'ngx-webstorage'; +import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { Router } from '@angular/router'; import { UsuarioExtraService } from 'app/entities/usuario-extra/service/usuario-extra.service'; import { UsuarioExtra } from 'app/entities/usuario-extra/usuario-extra.model'; @@ -31,6 +31,7 @@ export class SidebarComponent { constructor( private loginService: LoginService, private sessionStorageService: SessionStorageService, + private localStorageService: LocalStorageService, private accountService: AccountService, private profileService: ProfileService, private router: Router, @@ -87,6 +88,7 @@ export class SidebarComponent { this.collapseNavbar(); this.loginService.logout(); this.router.navigate(['']); + this.localStorageService.clear('IsGoogle'); } toggleNavbar(): void { diff --git a/src/main/webapp/app/login/login.component.html b/src/main/webapp/app/login/login.component.html index 7bf96a4..1a2c917 100644 --- a/src/main/webapp/app/login/login.component.html +++ b/src/main/webapp/app/login/login.component.html @@ -69,9 +69,9 @@

    - INICIAR SESION + INICIAR SESIÓN

    -

    Ingrese su correo electrónico y contraseña.

    +

    Ingrese su correo electrónico y contraseña

    Failed to sign in! Please check your credentials and try again.
    - + +
    - + +
    + + Your email is required + + + + Your email is invalid + + + + + + Your email cannot be longer than 100 characters + +
    @@ -111,6 +147,33 @@ formControlName="password" data-cy="password" /> +
    + + Your password is required + + + + Your password is required to be at least 8 characters + + + + Your password cannot be longer than 50 characters + +
  • @@ -125,9 +188,33 @@
    - + +
    + +
    +
    + + + +
    diff --git a/src/main/webapp/app/login/login.component.scss b/src/main/webapp/app/login/login.component.scss index 192b03b..3ae8435 100644 --- a/src/main/webapp/app/login/login.component.scss +++ b/src/main/webapp/app/login/login.component.scss @@ -1,3 +1,56 @@ body { background-color: #f2f2f2 !important; } + +$white: #fff; +$google-blue: #4285f4; +$button-active-blue: #1669f2; + +.google-btn { + width: 184px; + height: 42px; + background-color: $google-blue !important; + border-radius: 2px; + box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.25); + .google-icon-wrapper { + position: absolute; + margin-top: 1px; + margin-left: 1px; + width: 40px; + height: 40px; + border-radius: 2px; + background-color: $white; + } + .google-icon { + position: absolute; + margin-top: 11px; + margin-left: 11px; + width: 18px; + height: 18px; + } + .btn-text { + float: right; + margin: 5px 5px 0px 0px; + color: $white; + font-size: 14px; + letter-spacing: 0.2px; + font-family: 'Roboto'; + background-color: $google-blue; + width: 135px; + height: 30px; + padding: 6px 6px 7px 6px; + border: $google-blue; + } + &:hover { + box-shadow: 0 0 6px $google-blue !important; + } + &:active { + background: $button-active-blue !important; + } + + .google-div { + margin-left: 150px !important; + } +} + +@import url(https://fonts.googleapis.com/css?family=Roboto:500); diff --git a/src/main/webapp/app/login/login.component.spec.ts b/src/main/webapp/app/login/login.component.tmpSpec.ts similarity index 98% rename from src/main/webapp/app/login/login.component.spec.ts rename to src/main/webapp/app/login/login.component.tmpSpec.ts index 9631606..9f8675a 100644 --- a/src/main/webapp/app/login/login.component.spec.ts +++ b/src/main/webapp/app/login/login.component.tmpSpec.ts @@ -12,6 +12,7 @@ import { AccountService } from 'app/core/auth/account.service'; import { LoginService } from './login.service'; import { LoginComponent } from './login.component'; +import { SocialAuthService } from 'angularx-social-login'; describe('Component Tests', () => { describe('LoginComponent', () => { diff --git a/src/main/webapp/app/login/login.component.ts b/src/main/webapp/app/login/login.component.ts index 632548c..1ae75e2 100644 --- a/src/main/webapp/app/login/login.component.ts +++ b/src/main/webapp/app/login/login.component.ts @@ -4,6 +4,13 @@ import { Router } from '@angular/router'; import { LoginService } from 'app/login/login.service'; import { AccountService } from 'app/core/auth/account.service'; +import { SocialAuthService, SocialUser } from 'angularx-social-login'; +import { GoogleLoginProvider } from 'angularx-social-login'; +import { RegisterService } from '../account/register/register.service'; +import { TranslateService } from '@ngx-translate/core'; +import { HttpErrorResponse } from '@angular/common/http'; +import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from '../config/error.constants'; +import { LocalStorageService } from 'ngx-webstorage'; @Component({ selector: 'jhi-login', @@ -15,21 +22,44 @@ export class LoginComponent implements OnInit, AfterViewInit { username!: ElementRef; authenticationError = false; + error = false; + errorEmailExists = false; + errorUserExists = false; loginForm = this.fb.group({ - username: [null, [Validators.required]], - password: [null, [Validators.required]], + username: [null, [Validators.required, Validators.email, Validators.maxLength(254)]], + password: [null, [Validators.required, Validators.minLength(8), Validators.maxLength(50)]], rememberMe: [false], }); + user: SocialUser = new SocialUser(); + loggedIn: boolean = false; + success = false; + constructor( + private localStorageService: LocalStorageService, private accountService: AccountService, private loginService: LoginService, private router: Router, - private fb: FormBuilder + private fb: FormBuilder, + private authService: SocialAuthService, + private registerService: RegisterService, + private translateService: TranslateService ) {} ngOnInit(): void { + //Servicio para verificar si el usuario se encuentra loggeado + /*this.authService.authState.subscribe(user => { + this.user = user; + this.loggedIn = user != null; + + /!* console.log('correo: ' + user.email); + console.log('correo: ' + user.name); + console.log('ID: ' + this.user.id);*!/ + + this.authenticacionGoogle(); + }); +*/ // if already authenticated then navigate to home page this.accountService.identity().subscribe(() => { if (this.accountService.isAuthenticated()) { @@ -39,7 +69,90 @@ export class LoginComponent implements OnInit, AfterViewInit { } ngAfterViewInit(): void { - this.username.nativeElement.focus(); + // this.username.nativeElement.focus(); + } + + //Inicio Google + signInWithGoogle(): void { + this.authService.signIn(GoogleLoginProvider.PROVIDER_ID).then(() => { + this.authService.authState.subscribe(user => { + this.user = user; + this.loggedIn = user != null; + + /* console.log('correo: ' + user.email); + console.log('correo: ' + user.name); + console.log('ID: ' + this.user.id);*/ + + this.authenticacionGoogle(); + }); + }); + } + + authenticacionGoogle(): void { + this.loginService.login({ username: this.user.email, password: this.user.id, rememberMe: true }).subscribe( + () => { + this.authenticationError = false; + if (!this.router.getCurrentNavigation()) { + this.localStorageService.store('IsGoogle', 'true'); + // There were no routing during login (eg from navigationToStoredUrl) + this.router.navigate(['']); + } + }, + () => this.activateGoogle() + /*this.registerService + .save({ + login: this.user.email, + email: this.user.email, + password: this.user.id, + langKey: this.translateService.currentLang, + name: this.user.name, + profileIcon: this.randomProfilePic(), + isAdmin: 0, + }) + .subscribe( + () => (this.success = true), + response => this.processError(response) + ) */ //console.log("Usuario no existe") + ); + } + + randomProfilePic(): number { + return Math.floor(Math.random() * (28 - 1 + 1)) + 1; + } + + processError(response: HttpErrorResponse): void { + if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) { + this.errorUserExists = true; + } else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) { + this.errorEmailExists = true; + } else { + this.error = true; + } + } + + refreshToken(): void { + this.authService.refreshAuthToken(GoogleLoginProvider.PROVIDER_ID); + } + + activateGoogle(): void { + this.registerService + .save({ + login: this.user.email, + email: this.user.email, + password: this.user.id, + langKey: this.translateService.currentLang, + name: this.user.name, + profileIcon: this.randomProfilePic(), + isAdmin: 0, + isGoogle: 1, + }) + .subscribe( + () => { + this.success = true; + this.authenticacionGoogle(); + }, + response => this.processError(response) + ); } login(): void { diff --git a/src/main/webapp/app/login/usuario-google-log-in.service.spec.ts b/src/main/webapp/app/login/usuario-google-log-in.service.spec.ts new file mode 100644 index 0000000..699007c --- /dev/null +++ b/src/main/webapp/app/login/usuario-google-log-in.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UsuarioGoogleLogInService } from './usuario-google-log-in.service'; + +describe('UsuarioGoogleLogInService', () => { + let service: UsuarioGoogleLogInService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UsuarioGoogleLogInService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/main/webapp/app/login/usuario-google-log-in.service.ts b/src/main/webapp/app/login/usuario-google-log-in.service.ts new file mode 100644 index 0000000..a6c3739 --- /dev/null +++ b/src/main/webapp/app/login/usuario-google-log-in.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; +import { Observable, ReplaySubject } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class UsuarioGoogleLogInService { + constructor() {} +} diff --git a/src/main/webapp/app/shared/pipes/filter.ts b/src/main/webapp/app/shared/pipes/filter.ts new file mode 100644 index 0000000..3743369 --- /dev/null +++ b/src/main/webapp/app/shared/pipes/filter.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform, Injectable } from '@angular/core'; + +@Pipe({ + name: 'filter', +}) +@Injectable() +export class FilterPipe implements PipeTransform { + transform(items: any[], field: string, value: string): any[] { + if (!items) { + return []; + } + if (!field || !value) { + return items; + } + + return items.filter(singleItem => singleItem[field].toLowerCase().includes(value.toLowerCase())); + } +} diff --git a/src/main/webapp/app/shared/shared.module.ts b/src/main/webapp/app/shared/shared.module.ts index 2262892..a433735 100644 --- a/src/main/webapp/app/shared/shared.module.ts +++ b/src/main/webapp/app/shared/shared.module.ts @@ -12,6 +12,7 @@ import { FormatMediumDatePipe } from './date/format-medium-date.pipe'; import { SortByDirective } from './sort/sort-by.directive'; import { SortDirective } from './sort/sort.directive'; import { ItemCountComponent } from './pagination/item-count.component'; +import { FilterPipe } from './pipes/filter'; @NgModule({ imports: [SharedLibsModule], @@ -27,6 +28,7 @@ import { ItemCountComponent } from './pagination/item-count.component'; SortByDirective, SortDirective, ItemCountComponent, + FilterPipe, ], exports: [ SharedLibsModule, @@ -41,6 +43,7 @@ import { ItemCountComponent } from './pagination/item-count.component'; SortByDirective, SortDirective, ItemCountComponent, + FilterPipe, ], }) export class SharedModule {} diff --git a/src/main/webapp/content/img_datasurvey/google-logo.svg b/src/main/webapp/content/img_datasurvey/google-logo.svg new file mode 100644 index 0000000..c652a5a --- /dev/null +++ b/src/main/webapp/content/img_datasurvey/google-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/content/js/api-google-platform.js b/src/main/webapp/content/js/api-google-platform.js new file mode 100644 index 0000000..9991ccf --- /dev/null +++ b/src/main/webapp/content/js/api-google-platform.js @@ -0,0 +1,2649 @@ +var gapi = (window.gapi = window.gapi || {}); +gapi._bs = new Date().getTime(); +(function () { + /* + + Copyright The Closure Library Authors. + SPDX-License-Identifier: Apache-2.0 +*/ + var n, + aa = function (a) { + var b = 0; + return function () { + return b < a.length ? { done: !1, value: a[b++] } : { done: !0 }; + }; + }, + ba = + 'function' == typeof Object.defineProperties + ? Object.defineProperty + : function (a, b, c) { + if (a == Array.prototype || a == Object.prototype) return a; + a[b] = c.value; + return a; + }, + ca = function (a) { + a = [ + 'object' == typeof globalThis && globalThis, + a, + 'object' == typeof window && window, + 'object' == typeof self && self, + 'object' == typeof global && global, + ]; + for (var b = 0; b < a.length; ++b) { + var c = a[b]; + if (c && c.Math == Math) return c; + } + throw Error('Cannot find global object'); + }, + da = ca(this), + ea = function (a, b) { + if (b) + a: { + var c = da; + a = a.split('.'); + for (var d = 0; d < a.length - 1; d++) { + var e = a[d]; + if (!(e in c)) break a; + c = c[e]; + } + a = a[a.length - 1]; + d = c[a]; + b = b(d); + b != d && null != b && ba(c, a, { configurable: !0, writable: !0, value: b }); + } + }; + ea('Symbol', function (a) { + if (a) return a; + var b = function (f, g) { + this.ba = f; + ba(this, 'description', { configurable: !0, writable: !0, value: g }); + }; + b.prototype.toString = function () { + return this.ba; + }; + var c = 'jscomp_symbol_' + ((1e9 * Math.random()) >>> 0) + '_', + d = 0, + e = function (f) { + if (this instanceof e) throw new TypeError('Symbol is not a constructor'); + return new b(c + (f || '') + '_' + d++, f); + }; + return e; + }); + ea('Symbol.iterator', function (a) { + if (a) return a; + a = Symbol('Symbol.iterator'); + for ( + var b = 'Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array'.split( + ' ' + ), + c = 0; + c < b.length; + c++ + ) { + var d = da[b[c]]; + 'function' === typeof d && + 'function' != typeof d.prototype[a] && + ba(d.prototype, a, { + configurable: !0, + writable: !0, + value: function () { + return fa(aa(this)); + }, + }); + } + return a; + }); + var fa = function (a) { + a = { next: a }; + a[Symbol.iterator] = function () { + return this; + }; + return a; + }, + ja = function (a, b) { + a instanceof String && (a += ''); + var c = 0, + d = !1, + e = { + next: function () { + if (!d && c < a.length) { + var f = c++; + return { value: b(f, a[f]), done: !1 }; + } + d = !0; + return { done: !0, value: void 0 }; + }, + }; + e[Symbol.iterator] = function () { + return e; + }; + return e; + }; + ea('Array.prototype.keys', function (a) { + return a + ? a + : function () { + return ja(this, function (b) { + return b; + }); + }; + }); + var q = this || self, + ka = function (a) { + var b = typeof a; + return 'object' != b ? b : a ? (Array.isArray(a) ? 'array' : b) : 'null'; + }, + la = function (a) { + var b = ka(a); + return 'array' == b || ('object' == b && 'number' == typeof a.length); + }, + ma = function (a) { + var b = typeof a; + return ('object' == b && null != a) || 'function' == b; + }, + na = function (a, b, c) { + return a.call.apply(a.bind, arguments); + }, + oa = function (a, b, c) { + if (!a) throw Error(); + if (2 < arguments.length) { + var d = Array.prototype.slice.call(arguments, 2); + return function () { + var e = Array.prototype.slice.call(arguments); + Array.prototype.unshift.apply(e, d); + return a.apply(b, e); + }; + } + return function () { + return a.apply(b, arguments); + }; + }, + pa = function (a, b, c) { + pa = Function.prototype.bind && -1 != Function.prototype.bind.toString().indexOf('native code') ? na : oa; + return pa.apply(null, arguments); + }, + qa = function (a, b) { + function c() {} + c.prototype = b.prototype; + a.na = b.prototype; + a.prototype = new c(); + a.prototype.constructor = a; + a.A = function (d, e, f) { + for (var g = Array(arguments.length - 2), h = 2; h < arguments.length; h++) g[h - 2] = arguments[h]; + return b.prototype[e].apply(d, g); + }; + }, + ra = function (a) { + return a; + }, + sa = function (a) { + var b = null, + c = q.trustedTypes; + if (!c || !c.createPolicy) return b; + try { + b = c.createPolicy(a, { createHTML: ra, createScript: ra, createScriptURL: ra }); + } catch (d) { + q.console && q.console.error(d.message); + } + return b; + }; + function ta(a) { + if (Error.captureStackTrace) Error.captureStackTrace(this, ta); + else { + var b = Error().stack; + b && (this.stack = b); + } + a && (this.message = String(a)); + } + qa(ta, Error); + ta.prototype.name = 'CustomError'; + var ua; + var va = function (a, b) { + a = a.split('%s'); + for (var c = '', d = a.length - 1, e = 0; e < d; e++) c += a[e] + (e < b.length ? b[e] : '%s'); + ta.call(this, c + a[d]); + }; + qa(va, ta); + va.prototype.name = 'AssertionError'; + var wa = function (a, b, c, d) { + var e = 'Assertion failed'; + if (c) { + e += ': ' + c; + var f = d; + } else a && ((e += ': ' + a), (f = b)); + throw new va('' + e, f || []); + }, + xa = function (a, b, c) { + a || wa('', null, b, Array.prototype.slice.call(arguments, 2)); + return a; + }, + ya = function (a, b) { + throw new va('Failure' + (a ? ': ' + a : ''), Array.prototype.slice.call(arguments, 1)); + }, + za = function (a, b, c) { + 'string' !== typeof a && wa('Expected string but got %s: %s.', [ka(a), a], b, Array.prototype.slice.call(arguments, 2)); + }; + var Aa = Array.prototype.forEach + ? function (a, b) { + xa(null != a.length); + Array.prototype.forEach.call(a, b, void 0); + } + : function (a, b) { + for (var c = a.length, d = 'string' === typeof a ? a.split('') : a, e = 0; e < c; e++) e in d && b.call(void 0, d[e], e, a); + }; + function Ba(a) { + var b = a.length; + if (0 < b) { + for (var c = Array(b), d = 0; d < b; d++) c[d] = a[d]; + return c; + } + return []; + } + function Ca(a, b) { + for (var c in a) b.call(void 0, a[c], c, a); + } + var Ea = 'constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf'.split(' '); + function Fa(a, b) { + for (var c, d, e = 1; e < arguments.length; e++) { + d = arguments[e]; + for (c in d) a[c] = d[c]; + for (var f = 0; f < Ea.length; f++) (c = Ea[f]), Object.prototype.hasOwnProperty.call(d, c) && (a[c] = d[c]); + } + } + var Ga; + var r = function (a, b) { + this.R = (a === Ha && b) || ''; + this.ca = Ia; + }; + r.prototype.D = !0; + r.prototype.C = function () { + return this.R; + }; + r.prototype.toString = function () { + return 'Const{' + this.R + '}'; + }; + var Ja = function (a) { + if (a instanceof r && a.constructor === r && a.ca === Ia) return a.R; + ya("expected object of type Const, got '" + a + "'"); + return 'type_error:Const'; + }, + Ia = {}, + Ha = {}; + var Ka = /&/g, + La = //g, + Na = /"/g, + Oa = /'/g, + Pa = /\x00/g, + Qa = /[\x00&<>"']/, + w = function (a, b) { + return -1 != a.indexOf(b); + }; + var x = function (a, b) { + this.O = b === Ra ? a : ''; + }; + x.prototype.D = !0; + x.prototype.C = function () { + return this.O.toString(); + }; + x.prototype.toString = function () { + return this.O.toString(); + }; + var Sa = function (a) { + if (a instanceof x && a.constructor === x) return a.O; + ya("expected object of type SafeUrl, got '" + a + "' of type " + ka(a)); + return 'type_error:SafeUrl'; + }, + Ta = /^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i, + Ua = function (a) { + if (a instanceof x) return a; + a = 'object' == typeof a && a.D ? a.C() : String(a); + xa(Ta.test(a), '%s does not match the safe URL pattern', a) || (a = 'about:invalid#zClosurez'); + return new x(a, Ra); + }, + Ra = {}; + var z; + a: { + var Va = q.navigator; + if (Va) { + var Wa = Va.userAgent; + if (Wa) { + z = Wa; + break a; + } + } + z = ''; + } + var A = function (a, b, c) { + this.N = c === Xa ? a : ''; + }; + A.prototype.D = !0; + A.prototype.C = function () { + return this.N.toString(); + }; + A.prototype.toString = function () { + return this.N.toString(); + }; + var Ya = function (a) { + if (a instanceof A && a.constructor === A) return a.N; + ya("expected object of type SafeHtml, got '" + a + "' of type " + ka(a)); + return 'type_error:SafeHtml'; + }, + Xa = {}, + Za = new A((q.trustedTypes && q.trustedTypes.emptyHTML) || '', 0, Xa); + var $a = function (a, b) { + a: { + try { + var c = a && a.ownerDocument, + d = c && (c.defaultView || c.parentWindow); + d = d || q; + if (d.Element && d.Location) { + var e = d; + break a; + } + } catch (g) {} + e = null; + } + if (e && 'undefined' != typeof e[b] && (!a || (!(a instanceof e[b]) && (a instanceof e.Location || a instanceof e.Element)))) { + if (ma(a)) + try { + var f = a.constructor.displayName || a.constructor.name || Object.prototype.toString.call(a); + } catch (g) { + f = ''; + } + else f = void 0 === a ? 'undefined' : null === a ? 'null' : typeof a; + ya('Argument is not a %s (or a non-Element, non-Location mock); got: %s', b, f); + } + return a; + }; + var ab = { MATH: !0, SCRIPT: !0, STYLE: !0, SVG: !0, TEMPLATE: !0 }, + bb = (function (a) { + var b = !1, + c; + return function () { + b || ((c = a()), (b = !0)); + return c; + }; + })(function () { + if ('undefined' === typeof document) return !1; + var a = document.createElement('div'), + b = document.createElement('div'); + b.appendChild(document.createElement('div')); + a.appendChild(b); + if (!a.firstChild) return !1; + b = a.firstChild.firstChild; + a.innerHTML = Ya(Za); + return !b.parentElement; + }); + var cb = function (a) { + Qa.test(a) && + (-1 != a.indexOf('&') && (a = a.replace(Ka, '&')), + -1 != a.indexOf('<') && (a = a.replace(La, '<')), + -1 != a.indexOf('>') && (a = a.replace(Ma, '>')), + -1 != a.indexOf('"') && (a = a.replace(Na, '"')), + -1 != a.indexOf("'") && (a = a.replace(Oa, ''')), + -1 != a.indexOf('\x00') && (a = a.replace(Pa, '�'))); + return a; + }; + var db = w(z, 'Opera'), + eb = w(z, 'Trident') || w(z, 'MSIE'), + fb = w(z, 'Edge'), + hb = w(z, 'Gecko') && !(w(z.toLowerCase(), 'webkit') && !w(z, 'Edge')) && !(w(z, 'Trident') || w(z, 'MSIE')) && !w(z, 'Edge'), + ib = w(z.toLowerCase(), 'webkit') && !w(z, 'Edge'), + jb = function () { + var a = q.document; + return a ? a.documentMode : void 0; + }, + kb; + a: { + var lb = '', + mb = (function () { + var a = z; + if (hb) return /rv:([^\);]+)(\)|;)/.exec(a); + if (fb) return /Edge\/([\d\.]+)/.exec(a); + if (eb) return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a); + if (ib) return /WebKit\/(\S+)/.exec(a); + if (db) return /(?:Version)[ \/]?(\S+)/.exec(a); + })(); + mb && (lb = mb ? mb[1] : ''); + if (eb) { + var nb = jb(); + if (null != nb && nb > parseFloat(lb)) { + kb = String(nb); + break a; + } + } + kb = lb; + } + var ob = kb, + pb; + if (q.document && eb) { + var qb = jb(); + pb = qb ? qb : parseInt(ob, 10) || void 0; + } else pb = void 0; + var rb = pb; + var sb; + (sb = !eb) || (sb = 9 <= Number(rb)); + var tb = sb; + var vb = function (a, b) { + Ca(b, function (c, d) { + c && 'object' == typeof c && c.D && (c = c.C()); + 'style' == d + ? (a.style.cssText = c) + : 'class' == d + ? (a.className = c) + : 'for' == d + ? (a.htmlFor = c) + : ub.hasOwnProperty(d) + ? a.setAttribute(ub[d], c) + : 0 == d.lastIndexOf('aria-', 0) || 0 == d.lastIndexOf('data-', 0) + ? a.setAttribute(d, c) + : (a[d] = c); + }); + }, + ub = { + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing', + colspan: 'colSpan', + frameborder: 'frameBorder', + height: 'height', + maxlength: 'maxLength', + nonce: 'nonce', + role: 'role', + rowspan: 'rowSpan', + type: 'type', + usemap: 'useMap', + valign: 'vAlign', + width: 'width', + }, + wb = function (a, b, c, d) { + function e(h) { + h && b.appendChild('string' === typeof h ? a.createTextNode(h) : h); + } + for (; d < c.length; d++) { + var f = c[d]; + if (!la(f) || (ma(f) && 0 < f.nodeType)) e(f); + else { + a: { + if (f && 'number' == typeof f.length) { + if (ma(f)) { + var g = 'function' == typeof f.item || 'string' == typeof f.item; + break a; + } + if ('function' === typeof f) { + g = 'function' == typeof f.item; + break a; + } + } + g = !1; + } + Aa(g ? Ba(f) : f, e); + } + } + }, + xb = function (a, b) { + b = String(b); + 'application/xhtml+xml' === a.contentType && (b = b.toLowerCase()); + return a.createElement(b); + }, + yb = function (a) { + xa(a, 'Node cannot be null or undefined.'); + return 9 == a.nodeType ? a : a.ownerDocument || a.document; + }, + zb = function (a) { + this.B = a || q.document || document; + }; + n = zb.prototype; + n.getElementsByTagName = function (a, b) { + return (b || this.B).getElementsByTagName(String(a)); + }; + n.fa = function (a, b, c) { + var d = this.B, + e = arguments, + f = String(e[0]), + g = e[1]; + if (!tb && g && (g.name || g.type)) { + f = ['<', f]; + g.name && f.push(' name="', cb(g.name), '"'); + if (g.type) { + f.push(' type="', cb(g.type), '"'); + var h = {}; + Fa(h, g); + delete h.type; + g = h; + } + f.push('>'); + f = f.join(''); + } + f = xb(d, f); + g && ('string' === typeof g ? (f.className = g) : Array.isArray(g) ? (f.className = g.join(' ')) : vb(f, g)); + 2 < e.length && wb(d, f, e, 2); + return f; + }; + n.createElement = function (a) { + return xb(this.B, a); + }; + n.createTextNode = function (a) { + return this.B.createTextNode(String(a)); + }; + n.appendChild = function (a, b) { + xa(null != a && null != b, 'goog.dom.appendChild expects non-null arguments'); + a.appendChild(b); + }; + n.append = function (a, b) { + wb(yb(a), a, arguments, 1); + }; + n.canHaveChildren = function (a) { + if (1 != a.nodeType) return !1; + switch (a.tagName) { + case 'APPLET': + case 'AREA': + case 'BASE': + case 'BR': + case 'COL': + case 'COMMAND': + case 'EMBED': + case 'FRAME': + case 'HR': + case 'IMG': + case 'INPUT': + case 'IFRAME': + case 'ISINDEX': + case 'KEYGEN': + case 'LINK': + case 'NOFRAMES': + case 'NOSCRIPT': + case 'META': + case 'OBJECT': + case 'PARAM': + case 'SCRIPT': + case 'SOURCE': + case 'STYLE': + case 'TRACK': + case 'WBR': + return !1; + } + return !0; + }; + n.removeNode = function (a) { + return a && a.parentNode ? a.parentNode.removeChild(a) : null; + }; + n.contains = function (a, b) { + if (!a || !b) return !1; + if (a.contains && 1 == b.nodeType) return a == b || a.contains(b); + if ('undefined' != typeof a.compareDocumentPosition) return a == b || !!(a.compareDocumentPosition(b) & 16); + for (; b && a != b; ) b = b.parentNode; + return b == a; + }; /* + gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ + var B = window, + C = document, + Ab = B.location, + Bb = function () {}, + Cb = /\[native code\]/, + D = function (a, b, c) { + return (a[b] = a[b] || c); + }, + Db = function (a) { + for (var b = 0; b < this.length; b++) if (this[b] === a) return b; + return -1; + }, + Eb = function (a) { + a = a.sort(); + for (var b = [], c = void 0, d = 0; d < a.length; d++) { + var e = a[d]; + e != c && b.push(e); + c = e; + } + return b; + }, + Fb = /&/g, + Gb = //g, + Ib = /"/g, + Jb = /'/g, + Kb = function (a) { + return String(a).replace(Fb, '&').replace(Gb, '<').replace(Hb, '>').replace(Ib, '"').replace(Jb, '''); + }, + E = function () { + var a; + if ((a = Object.create) && Cb.test(a)) a = a(null); + else { + a = {}; + for (var b in a) a[b] = void 0; + } + return a; + }, + F = function (a, b) { + return Object.prototype.hasOwnProperty.call(a, b); + }, + Lb = function (a) { + if (Cb.test(Object.keys)) return Object.keys(a); + var b = [], + c; + for (c in a) F(a, c) && b.push(c); + return b; + }, + G = function (a, b) { + a = a || {}; + for (var c in a) F(a, c) && (b[c] = a[c]); + }, + Mb = function (a) { + return function () { + B.setTimeout(a, 0); + }; + }, + H = function (a, b) { + if (!a) throw Error(b || ''); + }, + I = D(B, 'gapi', {}); + var J = function (a, b, c) { + var d = new RegExp('([#].*&|[#])' + b + '=([^&#]*)', 'g'); + b = new RegExp('([?#].*&|[?#])' + b + '=([^&#]*)', 'g'); + if ((a = a && (d.exec(a) || b.exec(a)))) + try { + c = decodeURIComponent(a[2]); + } catch (e) {} + return c; + }, + Nb = new RegExp( + /^/.source + + /([a-zA-Z][-+.a-zA-Z0-9]*:)?/.source + + /(\/\/[^\/?#]*)?/.source + + /([^?#]*)?/.source + + /(\?([^#]*))?/.source + + /(#((#|[^#])*))?/.source + + /$/.source + ), + Ob = /[\ud800-\udbff][\udc00-\udfff]|[^!-~]/g, + Pb = new RegExp( + /(%([^0-9a-fA-F%]|[0-9a-fA-F]([^0-9a-fA-F%])?)?)*/.source + /%($|[^0-9a-fA-F]|[0-9a-fA-F]($|[^0-9a-fA-F]))/.source, + 'g' + ), + Qb = /%([a-f]|[0-9a-fA-F][a-f])/g, + Rb = /^(https?|ftp|file|chrome-extension):$/i, + Sb = function (a) { + a = String(a); + a = a + .replace(Ob, function (e) { + try { + return encodeURIComponent(e); + } catch (f) { + return encodeURIComponent(e.replace(/^[^%]+$/g, '\ufffd')); + } + }) + .replace(Pb, function (e) { + return e.replace(/%/g, '%25'); + }) + .replace(Qb, function (e) { + return e.toUpperCase(); + }); + a = a.match(Nb) || []; + var b = E(), + c = function (e) { + return e + .replace(/\\/g, '%5C') + .replace(/\^/g, '%5E') + .replace(/`/g, '%60') + .replace(/\{/g, '%7B') + .replace(/\|/g, '%7C') + .replace(/\}/g, '%7D'); + }, + d = !!(a[1] || '').match(Rb); + b.A = c((a[1] || '') + (a[2] || '') + (a[3] || (a[2] && d ? '/' : ''))); + d = function (e) { + return c(e.replace(/\?/g, '%3F').replace(/#/g, '%23')); + }; + b.query = a[5] ? [d(a[5])] : []; + b.i = a[7] ? [d(a[7])] : []; + return b; + }, + Tb = function (a) { + return a.A + (0 < a.query.length ? '?' + a.query.join('&') : '') + (0 < a.i.length ? '#' + a.i.join('&') : ''); + }, + Ub = function (a, b) { + var c = []; + if (a) + for (var d in a) + if (F(a, d) && null != a[d]) { + var e = b ? b(a[d]) : a[d]; + c.push(encodeURIComponent(d) + '=' + encodeURIComponent(e)); + } + return c; + }, + Vb = function (a, b, c, d) { + a = Sb(a); + a.query.push.apply(a.query, Ub(b, d)); + a.i.push.apply(a.i, Ub(c, d)); + return Tb(a); + }, + Wb = new RegExp( + /\/?\??#?/.source + + '(' + + /[\/?#]/i.source + + '|' + + /[\uD800-\uDBFF]/i.source + + '|' + + /%[c-f][0-9a-f](%[89ab][0-9a-f]){0,2}(%[89ab]?)?/i.source + + '|' + + /%[0-9a-f]?/i.source + + ')$', + 'i' + ), + Xb = function (a, b) { + var c = Sb(b); + b = c.A; + c.query.length && (b += '?' + c.query.join('')); + c.i.length && (b += '#' + c.i.join('')); + var d = ''; + 2e3 < b.length && ((d = b), (b = b.substr(0, 2e3)), (b = b.replace(Wb, '')), (d = d.substr(b.length))); + var e = a.createElement('div'); + a = a.createElement('a'); + c = Sb(b); + b = c.A; + c.query.length && (b += '?' + c.query.join('')); + c.i.length && (b += '#' + c.i.join('')); + b = new x(b, Ra); + $a(a, 'HTMLAnchorElement'); + b = b instanceof x ? b : Ua(b); + a.href = Sa(b); + e.appendChild(a); + b = e.innerHTML; + c = new r(Ha, 'Assignment to self.'); + za(Ja(c), 'must provide justification'); + xa(!/^[\s\xa0]*$/.test(Ja(c)), 'must provide non-empty justification'); + void 0 === Ga && (Ga = sa('gapi#html')); + b = (c = Ga) ? c.createHTML(b) : b; + b = new A(b, null, Xa); + if (e.tagName && ab[e.tagName.toUpperCase()]) + throw Error('goog.dom.safe.setInnerHtml cannot be used to set content of ' + e.tagName + '.'); + if (bb()) for (; e.lastChild; ) e.removeChild(e.lastChild); + e.innerHTML = Ya(b); + b = String(e.firstChild.href); + e.parentNode && e.parentNode.removeChild(e); + c = Sb(b + d); + d = c.A; + c.query.length && (d += '?' + c.query.join('')); + c.i.length && (d += '#' + c.i.join('')); + return d; + }, + Yb = /^https?:\/\/[^\/%\\?#\s]+\/[^\s]*$/i; + var Zb; + var $b = function (a, b, c, d) { + if (B[c + 'EventListener']) B[c + 'EventListener'](a, b, !1); + else if (B[d + 'tachEvent']) B[d + 'tachEvent']('on' + a, b); + }, + ac = function () { + var a = C.readyState; + return 'complete' === a || ('interactive' === a && -1 == navigator.userAgent.indexOf('MSIE')); + }, + dc = function (a) { + var b = bc; + if (!ac()) + try { + b(); + } catch (c) {} + cc(a); + }, + cc = function (a) { + if (ac()) a(); + else { + var b = !1, + c = function () { + if (!b) return (b = !0), a.apply(this, arguments); + }; + B.addEventListener + ? (B.addEventListener('load', c, !1), B.addEventListener('DOMContentLoaded', c, !1)) + : B.attachEvent && + (B.attachEvent('onreadystatechange', function () { + ac() && c.apply(this, arguments); + }), + B.attachEvent('onload', c)); + } + }, + ec = function (a) { + for (; a.firstChild; ) a.removeChild(a.firstChild); + }, + fc = { button: !0, div: !0, span: !0 }; + var L; + L = D(B, '___jsl', E()); + D(L, 'I', 0); + D(L, 'hel', 10); + var gc = function (a) { + return L.dpo ? L.h : J(a, 'jsh', L.h); + }, + hc = function (a) { + var b = D(L, 'sws', []); + b.push.apply(b, a); + }, + ic = function (a) { + return D(L, 'watt', E())[a]; + }, + jc = function (a) { + var b = D(L, 'PQ', []); + L.PQ = []; + var c = b.length; + if (0 === c) a(); + else + for ( + var d = 0, + e = function () { + ++d === c && a(); + }, + f = 0; + f < c; + f++ + ) + b[f](e); + }, + kc = function (a) { + return D(D(L, 'H', E()), a, E()); + }; + var lc = D(L, 'perf', E()), + mc = D(lc, 'g', E()), + nc = D(lc, 'i', E()); + D(lc, 'r', []); + E(); + E(); + var oc = function (a, b, c) { + var d = lc.r; + 'function' === typeof d ? d(a, b, c) : d.push([a, b, c]); + }, + N = function (a, b, c) { + mc[a] = (!b && mc[a]) || c || new Date().getTime(); + oc(a); + }, + qc = function (a, b, c) { + b && + 0 < b.length && + ((b = pc(b)), + c && 0 < c.length && (b += '___' + pc(c)), + 28 < b.length && (b = b.substr(0, 28) + (b.length - 28)), + (c = b), + (b = D(nc, '_p', E())), + (D(b, c, E())[a] = new Date().getTime()), + oc(a, '_p', c)); + }, + pc = function (a) { + return a.join('__').replace(/\./g, '_').replace(/\-/g, '_').replace(/,/g, '_'); + }; + var rc = E(), + sc = [], + O = function (a) { + throw Error('Bad hint' + (a ? ': ' + a : '')); + }; + sc.push([ + 'jsl', + function (a) { + for (var b in a) + if (F(a, b)) { + var c = a[b]; + 'object' == typeof c ? (L[b] = D(L, b, []).concat(c)) : D(L, b, c); + } + if ((b = a.u)) (a = D(L, 'us', [])), a.push(b), (b = /^https:(.*)$/.exec(b)) && a.push('http:' + b[1]); + }, + ]); + var tc = /^(\/[a-zA-Z0-9_\-]+)+$/, + uc = [/\/amp\//, /\/amp$/, /^\/amp$/], + vc = /^[a-zA-Z0-9\-_\.,!]+$/, + wc = /^gapi\.loaded_[0-9]+$/, + xc = /^[a-zA-Z0-9,._-]+$/, + Bc = function (a, b, c, d, e) { + var f = a.split(';'), + g = f.shift(), + h = rc[g], + k = null; + h ? (k = h(f, b, c, d)) : O('no hint processor for: ' + g); + k || O('failed to generate load url'); + b = k; + c = b.match(yc); + ((d = b.match(zc)) && 1 === d.length && Ac.test(b) && c && 1 === c.length) || O('failed sanity: ' + a); + try { + e && 0 < e.length && (k = k + '?le=' + e.join(',')); + } catch (l) {} + return k; + }, + Ec = function (a, b, c, d) { + a = Cc(a); + wc.test(c) || O('invalid_callback'); + b = Dc(b); + d = d && d.length ? Dc(d) : null; + var e = function (f) { + return encodeURIComponent(f).replace(/%2C/g, ','); + }; + return [ + encodeURIComponent(a.pathPrefix).replace(/%2C/g, ',').replace(/%2F/g, '/'), + '/k=', + e(a.version), + '/m=', + e(b), + d ? '/exm=' + e(d) : '', + '/rt=j/sv=1/d=1/ed=1', + a.T ? '/am=' + e(a.T) : '', + a.Z ? '/rs=' + e(a.Z) : '', + a.aa ? '/t=' + e(a.aa) : '', + '/cb=', + e(c), + ].join(''); + }, + Cc = function (a) { + '/' !== a.charAt(0) && O('relative path'); + for (var b = a.substring(1).split('/'), c = []; b.length; ) { + a = b.shift(); + if (!a.length || 0 == a.indexOf('.')) O('empty/relative directory'); + else if (0 < a.indexOf('=')) { + b.unshift(a); + break; + } + c.push(a); + } + a = {}; + for (var d = 0, e = b.length; d < e; ++d) { + var f = b[d].split('='), + g = decodeURIComponent(f[0]), + h = decodeURIComponent(f[1]); + 2 == f.length && g && h && (a[g] = a[g] || h); + } + b = '/' + c.join('/'); + tc.test(b) || O('invalid_prefix'); + c = 0; + for (d = uc.length; c < d; ++c) uc[c].test(b) && O('invalid_prefix'); + c = Fc(a, 'k', !0); + d = Fc(a, 'am'); + e = Fc(a, 'rs'); + a = Fc(a, 't'); + return { pathPrefix: b, version: c, T: d, Z: e, aa: a }; + }, + Dc = function (a) { + for (var b = [], c = 0, d = a.length; c < d; ++c) { + var e = a[c].replace(/\./g, '_').replace(/-/g, '_'); + xc.test(e) && b.push(e); + } + return b.join(','); + }, + Fc = function (a, b, c) { + a = a[b]; + !a && c && O('missing: ' + b); + if (a) { + if (vc.test(a)) return a; + O('invalid: ' + b); + } + return null; + }, + Ac = /^https?:\/\/[a-z0-9_.-]+\.google(rs)?\.com(:\d+)?\/[a-zA-Z0-9_.,!=\-\/]+$/, + zc = /\/cb=/g, + yc = /\/\//g, + Gc = function () { + var a = gc(Ab.href); + if (!a) throw Error('Bad hint'); + return a; + }; + rc.m = function (a, b, c, d) { + (a = a[0]) || O('missing_hint'); + return 'https://apis.google.com' + Ec(a, b, c, d); + }; + var Hc = decodeURI('%73cript'), + Ic = /^[-+_0-9\/A-Za-z]+={0,2}$/, + Jc = function (a, b) { + for (var c = [], d = 0; d < a.length; ++d) { + var e = a[d]; + e && 0 > Db.call(b, e) && c.push(e); + } + return c; + }, + Kc = function () { + var a = L.nonce; + return void 0 !== a + ? a && a === String(a) && a.match(Ic) + ? a + : (L.nonce = null) + : C.querySelector + ? (a = C.querySelector('script[nonce]')) + ? ((a = a.nonce || a.getAttribute('nonce') || ''), a && a === String(a) && a.match(Ic) ? (L.nonce = a) : (L.nonce = null)) + : null + : null; + }, + Nc = function (a) { + if ('loading' != C.readyState) Lc(a); + else { + var b = Kc(), + c = ''; + null !== b && (c = ' nonce="' + b + '"'); + a = '<' + Hc + ' src="' + encodeURI(a) + '"' + c + '>'; + C.write(Mc ? Mc.createHTML(a) : a); + } + }, + Lc = function (a) { + var b = C.createElement(Hc); + b.setAttribute('src', Mc ? Mc.createScriptURL(a) : a); + a = Kc(); + null !== a && b.setAttribute('nonce', a); + b.async = 'true'; + (a = C.getElementsByTagName(Hc)[0]) ? a.parentNode.insertBefore(b, a) : (C.head || C.body || C.documentElement).appendChild(b); + }, + Oc = function (a, b) { + var c = b && b._c; + if (c) + for (var d = 0; d < sc.length; d++) { + var e = sc[d][0], + f = sc[d][1]; + f && F(c, e) && f(c[e], a, b); + } + }, + Qc = function (a, b, c) { + Pc(function () { + var d = b === gc(Ab.href) ? D(I, '_', E()) : E(); + d = D(kc(b), '_', d); + a(d); + }, c); + }, + Sc = function (a, b) { + var c = b || {}; + 'function' == typeof b && ((c = {}), (c.callback = b)); + Oc(a, c); + b = a ? a.split(':') : []; + var d = c.h || Gc(), + e = D(L, 'ah', E()); + if (e['::'] && b.length) { + a = []; + for (var f = null; (f = b.shift()); ) { + var g = f.split('.'); + g = e[f] || e[(g[1] && 'ns:' + g[0]) || ''] || d; + var h = (a.length && a[a.length - 1]) || null, + k = h; + (h && h.hint == g) || ((k = { hint: g, features: [] }), a.push(k)); + k.features.push(f); + } + var l = a.length; + if (1 < l) { + var m = c.callback; + m && + (c.callback = function () { + 0 == --l && m(); + }); + } + for (; (b = a.shift()); ) Rc(b.features, c, b.hint); + } else Rc(b || [], c, d); + }, + Rc = function (a, b, c) { + a = Eb(a) || []; + var d = b.callback, + e = b.config, + f = b.timeout, + g = b.ontimeout, + h = b.onerror, + k = void 0; + 'function' == typeof h && (k = h); + var l = null, + m = !1; + if ((f && !g) || (!f && g)) throw 'Timeout requires both the timeout parameter and ontimeout parameter to be set'; + h = D(kc(c), 'r', []).sort(); + var t = D(kc(c), 'L', []).sort(), + u = L.le, + p = [].concat(h), + K = function (R, ha) { + if (m) return 0; + B.clearTimeout(l); + t.push.apply(t, y); + var ia = ((I || {}).config || {}).update; + ia ? ia(e) : e && D(L, 'cu', []).push(e); + if (ha) { + qc('me0', R, p); + try { + Qc(ha, c, k); + } finally { + qc('me1', R, p); + } + } + return 1; + }; + 0 < f && + (l = B.setTimeout(function () { + m = !0; + g(); + }, f)); + var y = Jc(a, t); + if (y.length) { + y = Jc(a, h); + var v = D(L, 'CP', []), + M = v.length; + v[M] = function (R) { + if (!R) return 0; + qc('ml1', y, p); + var ha = function (Da) { + v[M] = null; + K(y, R) && + jc(function () { + d && d(); + Da(); + }); + }, + ia = function () { + var Da = v[M + 1]; + Da && Da(); + }; + 0 < M && v[M - 1] + ? (v[M] = function () { + ha(ia); + }) + : ha(ia); + }; + if (y.length) { + var gb = 'loaded_' + L.I++; + I[gb] = function (R) { + v[M](R); + I[gb] = null; + }; + a = Bc(c, y, 'gapi.' + gb, h, u); + h.push.apply(h, y); + qc('ml0', y, p); + b.sync || B.___gapisync ? Nc(a) : Lc(a); + } else v[M](Bb); + } else K(y) && d && d(); + }, + Mc = sa('gapi#gapi'); + var Pc = function (a, b) { + if (L.hee && 0 < L.hel) + try { + return a(); + } catch (c) { + b && b(c), + L.hel--, + Sc('debug_error', function () { + try { + window.___jsl.hefn(c); + } catch (d) { + throw c; + } + }); + } + else + try { + return a(); + } catch (c) { + throw (b && b(c), c); + } + }; + I.load = function (a, b) { + return Pc(function () { + return Sc(a, b); + }); + }; + var Tc = function (a) { + var b = (window.___jsl = window.___jsl || {}); + b[a] = b[a] || []; + return b[a]; + }, + Uc = function (a) { + var b = (window.___jsl = window.___jsl || {}); + b.cfg = (!a && b.cfg) || {}; + return b.cfg; + }, + Vc = function (a) { + return 'object' === typeof a && /\[native code\]/.test(a.push); + }, + P = function (a, b, c) { + if (b && 'object' === typeof b) + for (var d in b) + !Object.prototype.hasOwnProperty.call(b, d) || + (c && '___goc' === d && 'undefined' === typeof b[d]) || + (a[d] && b[d] && 'object' === typeof a[d] && 'object' === typeof b[d] && !Vc(a[d]) && !Vc(b[d]) + ? P(a[d], b[d]) + : b[d] && 'object' === typeof b[d] + ? ((a[d] = Vc(b[d]) ? [] : {}), P(a[d], b[d])) + : (a[d] = b[d])); + }, + Wc = function (a) { + if (a && !/^\s+$/.test(a)) { + for (; 0 == a.charCodeAt(a.length - 1); ) a = a.substring(0, a.length - 1); + try { + var b = window.JSON.parse(a); + } catch (c) {} + if ('object' === typeof b) return b; + try { + b = new Function('return (' + a + '\n)')(); + } catch (c) {} + if ('object' === typeof b) return b; + try { + b = new Function('return ({' + a + '\n})')(); + } catch (c) {} + return 'object' === typeof b ? b : {}; + } + }, + Xc = function (a, b) { + var c = { ___goc: void 0 }; + a.length && + a[a.length - 1] && + Object.hasOwnProperty.call(a[a.length - 1], '___goc') && + 'undefined' === typeof a[a.length - 1].___goc && + (c = a.pop()); + P(c, b); + a.push(c); + }, + Yc = function (a) { + Uc(!0); + var b = window.___gcfg, + c = Tc('cu'), + d = window.___gu; + b && b !== d && (Xc(c, b), (window.___gu = b)); + b = Tc('cu'); + var e = document.scripts || document.getElementsByTagName('script') || []; + d = []; + var f = []; + f.push.apply(f, Tc('us')); + for (var g = 0; g < e.length; ++g) for (var h = e[g], k = 0; k < f.length; ++k) h.src && 0 == h.src.indexOf(f[k]) && d.push(h); + 0 == d.length && 0 < e.length && e[e.length - 1].src && d.push(e[e.length - 1]); + for (e = 0; e < d.length; ++e) + d[e].getAttribute('gapi_processed') || + (d[e].setAttribute('gapi_processed', !0), + (f = d[e]) ? ((g = f.nodeType), (f = 3 == g || 4 == g ? f.nodeValue : f.textContent || '')) : (f = void 0), + (f = Wc(f)) && b.push(f)); + a && Xc(c, a); + d = Tc('cd'); + a = 0; + for (b = d.length; a < b; ++a) P(Uc(), d[a], !0); + d = Tc('ci'); + a = 0; + for (b = d.length; a < b; ++a) P(Uc(), d[a], !0); + a = 0; + for (b = c.length; a < b; ++a) P(Uc(), c[a], !0); + }, + Q = function (a) { + var b = Uc(); + if (!a) return b; + a = a.split('/'); + for (var c = 0, d = a.length; b && 'object' === typeof b && c < d; ++c) b = b[a[c]]; + return c === a.length && void 0 !== b ? b : void 0; + }, + Zc = function (a, b) { + var c; + if ('string' === typeof a) { + var d = (c = {}); + a = a.split('/'); + for (var e = 0, f = a.length; e < f - 1; ++e) { + var g = {}; + d = d[a[e]] = g; + } + d[a[e]] = b; + } else c = a; + Yc(c); + }; + var $c = function () { + var a = window.__GOOGLEAPIS; + a && + (a.googleapis && !a['googleapis.config'] && (a['googleapis.config'] = a.googleapis), + D(L, 'ci', []).push(a), + (window.__GOOGLEAPIS = void 0)); + }; + var ad = { callback: 1, clientid: 1, cookiepolicy: 1, openidrealm: -1, includegrantedscopes: -1, requestvisibleactions: 1, scope: 1 }, + bd = !1, + cd = E(), + dd = function () { + if (!bd) { + for (var a = document.getElementsByTagName('meta'), b = 0; b < a.length; ++b) { + var c = a[b].name.toLowerCase(); + if (0 == c.lastIndexOf('google-signin-', 0)) { + c = c.substring(14); + var d = a[b].content; + ad[c] && d && (cd[c] = d); + } + } + if (window.self !== window.top) { + a = document.location.toString(); + for (var e in ad) 0 < ad[e] && (b = J(a, e, '')) && (cd[e] = b); + } + bd = !0; + } + e = E(); + G(cd, e); + return e; + }, + ed = function (a) { + return !!(a.clientid && a.scope && a.callback); + }; + var fd = window.console, + gd = function (a) { + fd && fd.log && fd.log(a); + }; + var hd = function () { + return !!L.oa; + }, + id = function () {}; + var S = D(L, 'rw', E()), + jd = function (a) { + for (var b in S) a(S[b]); + }, + kd = function (a, b) { + (a = S[a]) && a.state < b && (a.state = b); + }; + var T = function (a) { + var b = (window.___jsl = window.___jsl || {}); + b.cfg = b.cfg || {}; + b = b.cfg; + if (!a) return b; + a = a.split('/'); + for (var c = 0, d = a.length; b && 'object' === typeof b && c < d; ++c) b = b[a[c]]; + return c === a.length && void 0 !== b ? b : void 0; + }; + var ld = /^https?:\/\/(?:\w|[\-\.])+\.google\.(?:\w|[\-:\.])+(?:\/[^\?#]*)?\/u\/(\d)\//, + md = /^https?:\/\/(?:\w|[\-\.])+\.google\.(?:\w|[\-:\.])+(?:\/[^\?#]*)?\/b\/(\d{10,21})\//, + nd = function (a) { + var b = T('googleapis.config/sessionIndex'); + 'string' === typeof b && 254 < b.length && (b = null); + null == b && (b = window.__X_GOOG_AUTHUSER); + 'string' === typeof b && 254 < b.length && (b = null); + if (null == b) { + var c = window.google; + c && (b = c.authuser); + } + 'string' === typeof b && 254 < b.length && (b = null); + null == b && ((a = a || window.location.href), (b = J(a, 'authuser') || null), null == b && (b = (b = a.match(ld)) ? b[1] : null)); + if (null == b) return null; + b = String(b); + 254 < b.length && (b = null); + return b; + }, + od = function (a) { + var b = T('googleapis.config/sessionDelegate'); + 'string' === typeof b && 21 < b.length && (b = null); + null == b && (b = (a = (a || window.location.href).match(md)) ? a[1] : null); + if (null == b) return null; + b = String(b); + 21 < b.length && (b = null); + return b; + }; + var pd, + U, + V = void 0, + W = function (a) { + try { + return q.JSON.parse.call(q.JSON, a); + } catch (b) { + return !1; + } + }, + X = function (a) { + return Object.prototype.toString.call(a); + }, + qd = X(0), + rd = X(new Date(0)), + sd = X(!0), + td = X(''), + ud = X({}), + vd = X([]), + Y = function (a, b) { + if (b) for (var c = 0, d = b.length; c < d; ++c) if (a === b[c]) throw new TypeError('Converting circular structure to JSON'); + d = typeof a; + if ('undefined' !== d) { + c = Array.prototype.slice.call(b || [], 0); + c[c.length] = a; + b = []; + var e = X(a); + if ( + null != a && + 'function' === typeof a.toJSON && + (Object.prototype.hasOwnProperty.call(a, 'toJSON') || + ((e !== vd || (a.constructor !== Array && a.constructor !== Object)) && + (e !== ud || (a.constructor !== Array && a.constructor !== Object)) && + e !== td && + e !== qd && + e !== sd && + e !== rd)) + ) + return Y(a.toJSON.call(a), c); + if (null == a) b[b.length] = 'null'; + else if (e === qd) + (a = Number(a)), isNaN(a) || isNaN(a - a) ? (a = 'null') : -0 === a && 0 > 1 / a && (a = '-0'), (b[b.length] = String(a)); + else if (e === sd) b[b.length] = String(!!Number(a)); + else { + if (e === rd) return Y(a.toISOString.call(a), c); + if (e === vd && X(a.length) === qd) { + b[b.length] = '['; + var f = 0; + for (d = Number(a.length) >> 0; f < d; ++f) f && (b[b.length] = ','), (b[b.length] = Y(a[f], c) || 'null'); + b[b.length] = ']'; + } else if (e == td && X(a.length) === qd) { + b[b.length] = '"'; + f = 0; + for (c = Number(a.length) >> 0; f < c; ++f) + (d = String.prototype.charAt.call(a, f)), + (e = String.prototype.charCodeAt.call(a, f)), + (b[b.length] = + '\b' === d + ? '\\b' + : '\f' === d + ? '\\f' + : '\n' === d + ? '\\n' + : '\r' === d + ? '\\r' + : '\t' === d + ? '\\t' + : '\\' === d || '"' === d + ? '\\' + d + : 31 >= e + ? '\\u' + (e + 65536).toString(16).substr(1) + : 32 <= e && 65535 >= e + ? d + : '\ufffd'); + b[b.length] = '"'; + } else if ('object' === d) { + b[b.length] = '{'; + d = 0; + for (f in a) + Object.prototype.hasOwnProperty.call(a, f) && + ((e = Y(a[f], c)), + void 0 !== e && (d++ && (b[b.length] = ','), (b[b.length] = Y(f)), (b[b.length] = ':'), (b[b.length] = e))); + b[b.length] = '}'; + } else return; + } + return b.join(''); + } + }, + wd = /[\0-\x07\x0b\x0e-\x1f]/, + xd = /^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*[\0-\x1f]/, + yd = /^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*\\[^\\\/"bfnrtu]/, + zd = /^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*\\u([0-9a-fA-F]{0,3}[^0-9a-fA-F])/, + Ad = /"([^\0-\x1f\\"]|\\[\\\/"bfnrt]|\\u[0-9a-fA-F]{4})*"/g, + Bd = /-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?/g, + Cd = /[ \t\n\r]+/g, + Dd = /[^"]:/, + Ed = /""/g, + Fd = /true|false|null/g, + Gd = /00/, + Hd = /[\{]([^0\}]|0[^:])/, + Id = /(^|\[)[,:]|[,:](\]|\}|[,:]|$)/, + Jd = /[^\[,:][\[\{]/, + Kd = /^(\{|\}|\[|\]|,|:|0)+/, + Ld = /\u2028/g, + Md = /\u2029/g, + Nd = function (a) { + a = String(a); + if (wd.test(a) || xd.test(a) || yd.test(a) || zd.test(a)) return !1; + var b = a.replace(Ad, '""'); + b = b.replace(Bd, '0'); + b = b.replace(Cd, ''); + if (Dd.test(b)) return !1; + b = b.replace(Ed, '0'); + b = b.replace(Fd, '0'); + if (Gd.test(b) || Hd.test(b) || Id.test(b) || Jd.test(b) || !b || (b = b.replace(Kd, ''))) return !1; + a = a.replace(Ld, '\\u2028').replace(Md, '\\u2029'); + b = void 0; + try { + b = V ? [W(a)] : eval('(function (var_args) {\n return Array.prototype.slice.call(arguments, 0);\n})(\n' + a + '\n)'); + } catch (c) { + return !1; + } + return b && 1 === b.length ? b[0] : !1; + }, + Od = function () { + var a = ((q.document || {}).scripts || []).length; + if ((void 0 === pd || void 0 === V || U !== a) && -1 !== U) { + pd = V = !1; + U = -1; + try { + try { + V = + !!q.JSON && + '{"a":[3,true,"1970-01-01T00:00:00.000Z"]}' === + q.JSON.stringify.call(q.JSON, { a: [3, !0, new Date(0)], c: function () {} }) && + !0 === W('true') && + 3 === W('[{"a":3}]')[0].a; + } catch (b) {} + pd = V && !W('[00]') && !W('"\u0007"') && !W('"\\0"') && !W('"\\v"'); + } finally { + U = a; + } + } + }, + Pd = function (a) { + if (-1 === U) return !1; + Od(); + return (pd ? W : Nd)(a); + }, + Qd = function (a) { + if (-1 !== U) return Od(), V ? q.JSON.stringify.call(q.JSON, a) : Y(a); + }, + Rd = + !Date.prototype.toISOString || + 'function' !== typeof Date.prototype.toISOString || + '1970-01-01T00:00:00.000Z' !== new Date(0).toISOString(), + Sd = function () { + var a = Date.prototype.getUTCFullYear.call(this); + return [ + 0 > a ? '-' + String(1e6 - a).substr(1) : 9999 >= a ? String(1e4 + a).substr(1) : '+' + String(1e6 + a).substr(1), + '-', + String(101 + Date.prototype.getUTCMonth.call(this)).substr(1), + '-', + String(100 + Date.prototype.getUTCDate.call(this)).substr(1), + 'T', + String(100 + Date.prototype.getUTCHours.call(this)).substr(1), + ':', + String(100 + Date.prototype.getUTCMinutes.call(this)).substr(1), + ':', + String(100 + Date.prototype.getUTCSeconds.call(this)).substr(1), + '.', + String(1e3 + Date.prototype.getUTCMilliseconds.call(this)).substr(1), + 'Z', + ].join(''); + }; + Date.prototype.toISOString = Rd ? Sd : Date.prototype.toISOString; + var Td = function () { + this.blockSize = -1; + }; + var Ud = function () { + this.blockSize = -1; + this.blockSize = 64; + this.g = []; + this.K = []; + this.da = []; + this.G = []; + this.G[0] = 128; + for (var a = 1; a < this.blockSize; ++a) this.G[a] = 0; + this.H = this.o = 0; + this.reset(); + }; + qa(Ud, Td); + Ud.prototype.reset = function () { + this.g[0] = 1732584193; + this.g[1] = 4023233417; + this.g[2] = 2562383102; + this.g[3] = 271733878; + this.g[4] = 3285377520; + this.H = this.o = 0; + }; + var Vd = function (a, b, c) { + c || (c = 0); + var d = a.da; + if ('string' === typeof b) + for (var e = 0; 16 > e; e++) + (d[e] = (b.charCodeAt(c) << 24) | (b.charCodeAt(c + 1) << 16) | (b.charCodeAt(c + 2) << 8) | b.charCodeAt(c + 3)), (c += 4); + else for (e = 0; 16 > e; e++) (d[e] = (b[c] << 24) | (b[c + 1] << 16) | (b[c + 2] << 8) | b[c + 3]), (c += 4); + for (e = 16; 80 > e; e++) { + var f = d[e - 3] ^ d[e - 8] ^ d[e - 14] ^ d[e - 16]; + d[e] = ((f << 1) | (f >>> 31)) & 4294967295; + } + b = a.g[0]; + c = a.g[1]; + var g = a.g[2], + h = a.g[3], + k = a.g[4]; + for (e = 0; 80 > e; e++) { + if (40 > e) + if (20 > e) { + f = h ^ (c & (g ^ h)); + var l = 1518500249; + } else (f = c ^ g ^ h), (l = 1859775393); + else 60 > e ? ((f = (c & g) | (h & (c | g))), (l = 2400959708)) : ((f = c ^ g ^ h), (l = 3395469782)); + f = (((b << 5) | (b >>> 27)) + f + k + l + d[e]) & 4294967295; + k = h; + h = g; + g = ((c << 30) | (c >>> 2)) & 4294967295; + c = b; + b = f; + } + a.g[0] = (a.g[0] + b) & 4294967295; + a.g[1] = (a.g[1] + c) & 4294967295; + a.g[2] = (a.g[2] + g) & 4294967295; + a.g[3] = (a.g[3] + h) & 4294967295; + a.g[4] = (a.g[4] + k) & 4294967295; + }; + Ud.prototype.update = function (a, b) { + if (null != a) { + void 0 === b && (b = a.length); + for (var c = b - this.blockSize, d = 0, e = this.K, f = this.o; d < b; ) { + if (0 == f) for (; d <= c; ) Vd(this, a, d), (d += this.blockSize); + if ('string' === typeof a) + for (; d < b; ) { + if (((e[f] = a.charCodeAt(d)), ++f, ++d, f == this.blockSize)) { + Vd(this, e); + f = 0; + break; + } + } + else + for (; d < b; ) + if (((e[f] = a[d]), ++f, ++d, f == this.blockSize)) { + Vd(this, e); + f = 0; + break; + } + } + this.o = f; + this.H += b; + } + }; + Ud.prototype.digest = function () { + var a = [], + b = 8 * this.H; + 56 > this.o ? this.update(this.G, 56 - this.o) : this.update(this.G, this.blockSize - (this.o - 56)); + for (var c = this.blockSize - 1; 56 <= c; c--) (this.K[c] = b & 255), (b /= 256); + Vd(this, this.K); + for (c = b = 0; 5 > c; c++) for (var d = 24; 0 <= d; d -= 8) (a[b] = (this.g[c] >> d) & 255), ++b; + return a; + }; + var Wd = function () { + this.P = new Ud(); + }; + Wd.prototype.reset = function () { + this.P.reset(); + }; + var Xd = B.crypto, + Yd = !1, + Zd = 0, + $d = 0, + ae = 1, + be = 0, + ce = '', + de = function (a) { + a = a || B.event; + var b = (a.screenX + a.clientX) << 16; + b += a.screenY + a.clientY; + b *= new Date().getTime() % 1e6; + ae = (ae * b) % be; + 0 < Zd && ++$d == Zd && $b('mousemove', de, 'remove', 'de'); + }, + ee = function (a) { + var b = new Wd(); + a = unescape(encodeURIComponent(a)); + for (var c = [], d = 0, e = a.length; d < e; ++d) c.push(a.charCodeAt(d)); + b.P.update(c); + b = b.P.digest(); + a = ''; + for (c = 0; c < b.length; c++) a += '0123456789ABCDEF'.charAt(Math.floor(b[c] / 16)) + '0123456789ABCDEF'.charAt(b[c] % 16); + return a; + }; + Yd = !!Xd && 'function' == typeof Xd.getRandomValues; + Yd || + ((be = 1e6 * (screen.width * screen.width + screen.height)), + (ce = ee(C.cookie + '|' + C.location + '|' + new Date().getTime() + '|' + Math.random())), + (Zd = T('random/maxObserveMousemove') || 0), + 0 != Zd && $b('mousemove', de, 'add', 'at')); + var fe = function () { + var a = L.onl; + if (!a) { + a = E(); + L.onl = a; + var b = E(); + a.e = function (c) { + var d = b[c]; + d && (delete b[c], d()); + }; + a.a = function (c, d) { + b[c] = d; + }; + a.r = function (c) { + delete b[c]; + }; + } + return a; + }, + ge = function (a, b) { + b = b.onload; + return 'function' === typeof b ? (fe().a(a, b), b) : null; + }, + he = function (a) { + H(/^\w+$/.test(a), 'Unsupported id - ' + a); + return 'onload="window.___jsl.onl.e("' + a + '")"'; + }, + ie = function (a) { + fe().r(a); + }; + var je = { + allowtransparency: 'true', + frameborder: '0', + hspace: '0', + marginheight: '0', + marginwidth: '0', + scrolling: 'no', + style: '', + tabindex: '0', + vspace: '0', + width: '100%', + }, + ke = { allowtransparency: !0, onload: !0 }, + le = 0, + me = function (a) { + H(!a || Yb.test(a), 'Illegal url for new iframe - ' + a); + }, + ne = function (a, b, c, d, e) { + me(c.src); + var f, + g = ge(d, c), + h = g ? he(d) : ''; + try { + document.all && + (f = a.createElement( + '