diff --git a/Gemfile b/Gemfile index 72c0c7bdf82..291ab73a93b 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ gem 'rqrcode' gem 'ruby-progressbar' gem 'ruby-saml' gem 'safe_target_blank', '>= 1.0.2' -gem 'saml_idp', github: '18F/saml_idp', tag: '0.19.3-18f' +gem 'saml_idp', github: '18F/saml_idp', tag: '0.20.0-18f' gem 'scrypt' gem 'simple_form', '>= 5.0.2' gem 'stringex', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 1b99491b670..89c453cc548 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,8 +34,8 @@ GIT GIT remote: https://github.com/18F/saml_idp.git - revision: 95369fdd9336773b9983c8de71eb35a8c92e9683 - tag: 0.19.3-18f + revision: f86b4c5ef4281a53b3f13a1db2c2e5839fdf077d + tag: 0.20.0-18f specs: saml_idp (0.19.3.pre.18f) activesupport @@ -560,7 +560,7 @@ GEM ffi (~> 1.0) rdoc (6.6.2) psych (>= 4.0.0) - redacted_struct (1.1.0) + redacted_struct (2.0.0) redcarpet (3.6.0) redis (5.0.6) redis-client (>= 0.9.0) diff --git a/app/assets/images/logo.png b/app/assets/images/email/logo.png similarity index 100% rename from app/assets/images/logo.png rename to app/assets/images/email/logo.png diff --git a/app/components/login_button_component.html.erb b/app/components/login_button_component.html.erb index eb808be865a..7fa458e02e4 100644 --- a/app/components/login_button_component.html.erb +++ b/app/components/login_button_component.html.erb @@ -3,5 +3,5 @@ **tag_options, class: css_class, ) do %> - Sign in with <%= content_tag(:span, APP_NAME, class: 'login-button__logo') %> -<% end %> \ No newline at end of file + Sign in with <%= inject_svg %> +<% end %> diff --git a/app/components/login_button_component.rb b/app/components/login_button_component.rb index 25b3a7d42b1..b6e16c74ac7 100644 --- a/app/components/login_button_component.rb +++ b/app/components/login_button_component.rb @@ -3,18 +3,40 @@ class LoginButtonComponent < BaseComponent VALID_COLORS = ['primary', 'primary-darker', 'primary-lighter'].freeze - attr_reader :color, :big, :tag_options + attr_reader :color, :big, :width, :height, :tag_options def initialize(color: 'primary', big: false, **tag_options) if !VALID_COLORS.include?(color) raise ArgumentError, "`color` #{color}} is invalid, expected one of #{VALID_COLORS}" end - @big = big + @width = big ? '11.1rem' : '7.4rem' + @height = big ? '1.5rem' : '1rem' @color = color @tag_options = tag_options end + def svg + Rails.root.join( + 'app', 'assets', 'images', + (color == 'primary-darker' ? 'logo-white.svg' : 'logo.svg') + ).read + end + + def inject_svg + # rubocop:disable Rails/OutputSafety + Nokogiri::HTML5.fragment(svg).tap do |doc| + doc.at_css('svg').tap do |svg| + svg[:role] = 'img' + svg[:class] = 'login-button__logo' + svg[:width] = width + svg[:height] = height + svg << "#{APP_NAME}" + end + end.to_s.html_safe + # rubocop:enable Rails/OutputSafety + end + def css_class classes = ['usa-button', *tag_options[:class]] classes << 'usa-button--big' if big diff --git a/app/components/login_button_component.scss b/app/components/login_button_component.scss index efa2e09b7e4..7ddb4c301bd 100644 --- a/app/components/login_button_component.scss +++ b/app/components/login_button_component.scss @@ -1,20 +1,7 @@ @use 'uswds-core' as *; -.login-button.usa-button--big > .login-button__logo { - font-size: 1.8rem; - margin-top: -2px; -} - .login-button__logo { - margin-left: 2px; - font-size: 1.45rem; - vertical-align: middle; - color: transparent; - background: no-repeat 100% url('logo.svg'); - - .login-button--primary-darker & { - background-image: url('logo-white.svg'); - } + margin-left: 3px; } .login-button.login-button--primary-lighter { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a982d7b95f8..e16f565cf4c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -234,6 +234,7 @@ def after_sign_in_path_for(_user) return fix_broken_personal_key_url if current_user.broken_personal_key? return user_session.delete(:stored_location) if user_session.key?(:stored_location) return reactivate_account_url if user_needs_to_reactivate_account? + return login_piv_cac_recommended_path if user_recommended_for_piv_cac? return second_mfa_reminder_url if user_needs_second_mfa_reminder? return sp_session_request_url_with_updated_params if sp_session.key?(:request_url) signed_in_url @@ -261,6 +262,15 @@ def user_needs_to_reactivate_account? resolved_authn_context_result.identity_proofing? end + def user_recommended_for_piv_cac? + current_user.piv_cac_recommended_dismissed_at.nil? && current_user.has_gov_or_mil_email? && + !user_already_has_piv? + end + + def user_already_has_piv? + MfaContext.new(current_user).piv_cac_configurations.present? + end + def pending_profile_newer_than_password_reset_profile? return false if current_user.pending_profile.blank? return false if current_user.password_reset_profile.blank? diff --git a/app/controllers/concerns/fraud_review_concern.rb b/app/controllers/concerns/fraud_review_concern.rb index a8294c567d8..53aeb101a66 100644 --- a/app/controllers/concerns/fraud_review_concern.rb +++ b/app/controllers/concerns/fraud_review_concern.rb @@ -26,9 +26,14 @@ def handle_fraud_rejection redirect_to_fraud_rejection if fraud_rejection? end + # Returns true if the user has not passed IPP at the post office and is + # flagged for fraud review, or has been rejected for fraud. + # Ultimately this is to allow users who fail at the post office to create another enrollment + # bypassing the typical flow of showing the Please Call or Fraud Rejection screens. def in_person_prevent_fraud_redirection? IdentityConfig.store.in_person_proofing_enforce_tmx && - current_user.ipp_enrollment_status_not_passed? + current_user.ipp_enrollment_status_not_passed? && + (fraud_review_pending? || fraud_rejection?) end def redirect_to_fraud_review diff --git a/app/controllers/concerns/mfa_setup_concern.rb b/app/controllers/concerns/mfa_setup_concern.rb index 0d5221f8cb4..e999c4c1376 100644 --- a/app/controllers/concerns/mfa_setup_concern.rb +++ b/app/controllers/concerns/mfa_setup_concern.rb @@ -56,6 +56,10 @@ def suggest_second_mfa? mfa_selection_count < 2 && mfa_context.enabled_mfa_methods_count < 2 end + def first_mfa_selection_path + confirmation_path(user_session[:mfa_selections].first) + end + def in_account_creation_flow? user_session[:in_account_creation_flow] || false end @@ -68,11 +72,21 @@ def mfa_selection_index user_session[:mfa_selection_index] || 0 end + def set_mfa_selections(selections) + user_session[:mfa_selections] = selections + end + def show_skip_additional_mfa_link? !(mfa_context.enabled_mfa_methods_count == 1 && mfa_context.webauthn_platform_configurations.count == 1) end + def check_if_possible_piv_user + if current_user.has_gov_or_mil_email? && current_user.piv_cac_recommended_dismissed_at.nil? + redirect_to login_piv_cac_recommended_path + end + end + private def track_user_registration_mfa_setup_complete_event diff --git a/app/controllers/concerns/unconfirmed_user_concern.rb b/app/controllers/concerns/unconfirmed_user_concern.rb index 71175d710f8..7bdfb0b1ac0 100644 --- a/app/controllers/concerns/unconfirmed_user_concern.rb +++ b/app/controllers/concerns/unconfirmed_user_concern.rb @@ -62,7 +62,7 @@ def process_valid_confirmation_token def process_unsuccessful_confirmation @confirmation_token = params[:confirmation_token] flash[:error] = unsuccessful_confirmation_error - redirect_to sign_up_email_resend_url(request_id: params[:_request_id]) + redirect_to sign_up_register_url(request_id: params[:_request_id]) end def unsuccessful_confirmation_error diff --git a/app/controllers/frontend_log_controller.rb b/app/controllers/frontend_log_controller.rb index 10308982b32..fd10cdcf9a6 100644 --- a/app/controllers/frontend_log_controller.rb +++ b/app/controllers/frontend_log_controller.rb @@ -48,6 +48,9 @@ class FrontendLogController < ApplicationController # rubocop:enable Layout/LineLength ALLOWED_EVENTS = %i[ + idv_camera_info_error + idv_camera_info_logged + idv_sdk_error_before_init idv_sdk_selfie_image_capture_closed_without_photo idv_sdk_selfie_image_capture_failed idv_sdk_selfie_image_capture_opened diff --git a/app/controllers/idv/address_controller.rb b/app/controllers/idv/address_controller.rb index 0b114849364..3dd3d8f42f3 100644 --- a/app/controllers/idv/address_controller.rb +++ b/app/controllers/idv/address_controller.rb @@ -11,12 +11,14 @@ class AddressController < ApplicationController def new analytics.idv_address_visit - @presenter = AddressPresenter.new(pii: idv_session.pii_from_doc) + @address_form = Idv::AddressForm.new(idv_session.pii_from_doc) + @presenter = AddressPresenter.new end def update clear_future_steps! - form_result = idv_form.submit(profile_params) + @address_form = Idv::AddressForm.new(idv_session.pii_from_doc) + form_result = @address_form.submit(profile_params) analytics.idv_address_submitted(**form_result.to_h) capture_address_edited(form_result) if form_result.success? @@ -33,7 +35,7 @@ def self.step_info action: :new, next_steps: [:verify_info], preconditions: ->(idv_session:, user:) { idv_session.remote_document_capture_complete? }, - undo_step: ->(idv_session:, user:) {}, + undo_step: ->(idv_session:, user:) { idv_session.updated_user_address = nil }, ) end @@ -44,14 +46,30 @@ def idv_form end def success - profile_params.each do |key, value| - idv_session.pii_from_doc[key] = value - end + idv_session.pii_from_doc = idv_session.pii_from_doc.merge( + address1: @address_form.address1, + address2: @address_form.address2, + city: @address_form.city, + state: @address_form.state, + zipcode: @address_form.zipcode, + ) + idv_session.updated_user_address = address_from_form redirect_to idv_verify_info_url end def failure - redirect_to idv_address_url + @presenter = AddressPresenter.new + render :new + end + + def address_from_form + Pii::Address.new( + address1: @address_form.address1, + address2: @address_form.address2, + city: @address_form.city, + state: @address_form.state, + zipcode: @address_form.zipcode, + ) end def profile_params diff --git a/app/controllers/sign_up/cancellations_controller.rb b/app/controllers/sign_up/cancellations_controller.rb index 4ff4472ff47..185f51056cd 100644 --- a/app/controllers/sign_up/cancellations_controller.rb +++ b/app/controllers/sign_up/cancellations_controller.rb @@ -55,7 +55,7 @@ def ensure_in_setup def ensure_valid_confirmation_token return if @user flash[:error] = error_message(@token_validator) - redirect_to sign_up_email_resend_url(request_id: params[:_request_id]) + redirect_to sign_up_register_url(request_id: params[:_request_id]) end def error_message(token_validator) diff --git a/app/controllers/sign_up/email_resend_controller.rb b/app/controllers/sign_up/email_resend_controller.rb deleted file mode 100644 index 016d16ad19d..00000000000 --- a/app/controllers/sign_up/email_resend_controller.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module SignUp - class EmailResendController < ApplicationController - def new - @user = User.new - @resend_email_confirmation_form = ResendEmailConfirmationForm.new - end - end -end diff --git a/app/controllers/sign_up/emails_controller.rb b/app/controllers/sign_up/emails_controller.rb index b46b4df0fd8..0bc16b51b00 100644 --- a/app/controllers/sign_up/emails_controller.rb +++ b/app/controllers/sign_up/emails_controller.rb @@ -9,7 +9,8 @@ def show @resend_confirmation = params[:resend].present? email = session.delete(:email) - @resend_email_confirmation_form = ResendEmailConfirmationForm.new(email:) + terms_accepted = session.delete(:terms_accepted) + @resend_email_confirmation_form = ResendEmailConfirmationForm.new(email:, terms_accepted:) render :show, locals: { email: email } end diff --git a/app/controllers/sign_up/registrations_controller.rb b/app/controllers/sign_up/registrations_controller.rb index 0a639228e17..83e420643e7 100644 --- a/app/controllers/sign_up/registrations_controller.rb +++ b/app/controllers/sign_up/registrations_controller.rb @@ -59,6 +59,7 @@ def process_successful_creation resend_confirmation = params[:user][:resend] session[:email] = @register_user_email_form.email + session[:terms_accepted] = @register_user_email_form.terms_accepted session[:sign_in_flow] = :create_account redirect_to sign_up_verify_email_url(resend: resend_confirmation) diff --git a/app/controllers/users/piv_cac_recommended_controller.rb b/app/controllers/users/piv_cac_recommended_controller.rb new file mode 100644 index 00000000000..c395283f734 --- /dev/null +++ b/app/controllers/users/piv_cac_recommended_controller.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Users + class PivCacRecommendedController < ApplicationController + include TwoFactorAuthenticatableMethods + include MfaSetupConcern + include SecureHeadersConcern + + before_action :confirm_user_authenticated_for_2fa_setup + before_action :apply_secure_headers_override + before_action :redirect_unless_user_email_is_gov_or_mil + + def show + @recommended_presenter = PivCacRecommendedPresenter.new(current_user) + analytics.piv_cac_recommended_visited + end + + def confirm + UpdateUser.new( + user: current_user, + attributes: { piv_cac_recommended_dismissed_at: Time.zone.now }, + ).call + analytics.piv_cac_recommended(action: :accepted) + set_mfa_selections(['piv_cac']) + redirect_to first_mfa_selection_path + end + + def skip + UpdateUser.new( + user: current_user, + attributes: { piv_cac_recommended_dismissed_at: Time.zone.now }, + ).call + analytics.piv_cac_recommended(action: :skipped) + redirect_to after_sign_in_path_for(current_user) + end + + private + + def redirect_unless_user_email_is_gov_or_mil + redirect_to after_sign_in_path_for(current_user) unless current_user.has_gov_or_mil_email? + end + end +end diff --git a/app/controllers/users/two_factor_authentication_setup_controller.rb b/app/controllers/users/two_factor_authentication_setup_controller.rb index d631b5b4e0c..492acb4bcee 100644 --- a/app/controllers/users/two_factor_authentication_setup_controller.rb +++ b/app/controllers/users/two_factor_authentication_setup_controller.rb @@ -7,6 +7,7 @@ class TwoFactorAuthenticationSetupController < ApplicationController before_action :authenticate_user before_action :confirm_user_authenticated_for_2fa_setup + before_action :check_if_possible_piv_user delegate :enabled_mfa_methods_count, to: :mfa_context @@ -73,12 +74,7 @@ def two_factor_options_presenter def process_valid_form user_session[:mfa_selections] = @two_factor_options_form.selection - - if user_session[:mfa_selections].first.present? - redirect_to confirmation_path(user_session[:mfa_selections].first) - else - redirect_to after_mfa_setup_path - end + redirect_to(first_mfa_selection_path || after_mfa_setup_path) end def two_factor_options_form_params diff --git a/app/forms/idv/address_form.rb b/app/forms/idv/address_form.rb index 904fe0341b6..4fc800782c9 100644 --- a/app/forms/idv/address_form.rb +++ b/app/forms/idv/address_form.rb @@ -10,11 +10,11 @@ class AddressForm attr_accessor(*ATTRIBUTES) def self.model_name - ActiveModel::Name.new(self, nil, 'Address') + ActiveModel::Name.new(self, nil, 'IdvForm') end def initialize(pii) - @pii = pii + set_ivars_with_pii(pii) @address_edited = false end @@ -33,13 +33,21 @@ def submit(params) private + def set_ivars_with_pii(pii) + pii = pii.symbolize_keys + @address1 = pii[:address1] + @address2 = pii[:address2] + @city = pii[:city] + @state = pii[:state] + @zipcode = pii[:zipcode] + end + def consume_params(params) - params.each do |key, value| - raise_invalid_address_parameter_error(key) unless ATTRIBUTES.include?(key.to_sym) - send(:"#{key}=", value) - if send(key) != @pii[key] && (send(key).present? || @pii[key].present?) + ATTRIBUTES.each do |attribute_name| + if send(attribute_name).to_s != params[attribute_name].to_s @address_edited = true end + send(:"#{attribute_name}=", params[attribute_name].to_s) end end diff --git a/app/forms/register_user_email_form.rb b/app/forms/register_user_email_form.rb index c705c3e4652..f712535b26c 100644 --- a/app/forms/register_user_email_form.rb +++ b/app/forms/register_user_email_form.rb @@ -48,13 +48,13 @@ def digested_base_email end def validate_terms_accepted - return if @terms_accepted || email_address_record&.user&.accepted_terms_at.present? + return if @terms_accepted errors.add(:terms_accepted, t('errors.registration.terms'), type: :terms) end def submit(params, instructions = nil) - @terms_accepted = params[:terms_accepted] == '1' + @terms_accepted = !!ActiveModel::Type::Boolean.new.cast(params[:terms_accepted]) build_user_and_email_address_with_email( email: params[:email], email_language: params[:email_language], diff --git a/app/forms/resend_email_confirmation_form.rb b/app/forms/resend_email_confirmation_form.rb index 020b9e8b85b..c4c59c9dfd2 100644 --- a/app/forms/resend_email_confirmation_form.rb +++ b/app/forms/resend_email_confirmation_form.rb @@ -3,7 +3,7 @@ class ResendEmailConfirmationForm include ActiveModel::Model - attr_reader :email + attr_reader :email, :terms_accepted def self.model_name ActiveModel::Name.new(self, nil, 'User') @@ -11,6 +11,7 @@ def self.model_name def initialize(params = {}) @email = params[:email] + @terms_accepted = params[:terms_accepted] end def resend diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 9eb95223b63..0b71c29398c 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -28,6 +28,7 @@ import FileInput from './file-input'; import UploadContext from '../context/upload'; import useCookie from '../hooks/use-cookie'; import useCounter from '../hooks/use-counter'; +import { useLogCameraInfo } from '../hooks/use-log-camera-info'; type AcuantImageAssessment = 'success' | 'glare' | 'blurry' | 'unsupported'; type ImageSource = 'acuant' | 'upload'; @@ -344,6 +345,10 @@ function AcuantCapture( // There's some pretty significant changes to this component when it's used for // selfie capture vs document image capture. This controls those changes. const selfieCapture = name === 'selfie'; + // When it's the back of the ID we want to log information about the camera + // This hook does that. + const isBackOfId = name === 'back'; + useLogCameraInfo({ isBackOfId, hasStartedCropping }); const { failedCaptureAttempts, diff --git a/app/javascript/packages/document-capture/components/document-capture-review-issues.tsx b/app/javascript/packages/document-capture/components/document-capture-review-issues.tsx index ff014d6ce7c..1e80d1b2862 100644 --- a/app/javascript/packages/document-capture/components/document-capture-review-issues.tsx +++ b/app/javascript/packages/document-capture/components/document-capture-review-issues.tsx @@ -52,7 +52,9 @@ function DocumentCaptureReviewIssues({ return ( <> {t('doc_auth.headings.review_issues')} - + {isSelfieCaptureEnabled && ( + + )}

2. {t('doc_auth.headings.document_capture_subheader_selfie')}

+

{t('doc_auth.info.selfie_capture_content')}

{flowPath === 'hybrid' && } {pageHeaderText} - + {isSelfieCaptureEnabled && ( + + )} void): unknown; initialize: AcuantInitialize; START_FAIL_CODE: string; REPEAT_FAIL_CODE: string; @@ -268,6 +269,16 @@ function AcuantContextProvider({ loadAcuantSdk(); } window.AcuantJavascriptWebSdk = getActualAcuantJavascriptWebSdk(); + + // Unclear if/how this is called. Implemented just in case, but this is untested. + window.AcuantJavascriptWebSdk.setUnexpectedErrorCallback((errorMessage) => { + trackEvent('idv_sdk_error_before_init', { + success: false, + error_message: errorMessage, + liveness_checking_required: isSelfieCaptureEnabled, + }); + }); + window.AcuantJavascriptWebSdk.initialize(credentials, endpoint, { onSuccess: () => { window.AcuantJavascriptWebSdk.start?.(() => { diff --git a/app/javascript/packages/document-capture/hooks/use-log-camera-info.ts b/app/javascript/packages/document-capture/hooks/use-log-camera-info.ts new file mode 100644 index 00000000000..3851e449fe2 --- /dev/null +++ b/app/javascript/packages/document-capture/hooks/use-log-camera-info.ts @@ -0,0 +1,130 @@ +import { useEffect, useContext, useRef } from 'react'; +import AnalyticsContext from '../context/analytics'; + +type TrackEventType = (event: string, payload?: object | undefined) => void; +interface CameraLog { + label: string; + frameRate: number | undefined; + height: number | undefined; + width: number | undefined; +} +type CameraLogs = (CameraLog | undefined)[]; + +function getConstraints(deviceId: string) { + return { + video: { + width: { + ideal: 999999, + }, + height: { + ideal: 999999, + }, + deviceId: { + exact: deviceId, + }, + }, + }; +} + +function getCameraInfo(videoTrack: MediaStreamTrack) { + const cameraInfo = { + label: videoTrack.label, + frameRate: videoTrack.getSettings().frameRate, + height: videoTrack.getSettings().height, + width: videoTrack.getSettings().width, + }; + return cameraInfo; +} + +async function updateConstraintsAndGetLogInfo( + videoDevice: MediaDeviceInfo, + trackEvent: TrackEventType, +) { + // See https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/facingMode + const updatedConstraints = getConstraints(videoDevice.deviceId); + try { + const stream = await navigator.mediaDevices.getUserMedia(updatedConstraints); + const videoTracks = stream.getVideoTracks(); + const cameras = videoTracks.map((videoTrack) => getCameraInfo(videoTrack)); + return cameras[0]; + } catch (error) { + trackEvent('idv_camera_info_error', { error }); + } +} + +function logsHaveSameValuesButDifferentName(logOne: CameraLog, logTwo: CameraLog) { + if ( + logOne.height === logTwo.height && + logOne.width === logTwo.width && + logOne.frameRate === logTwo.frameRate + ) { + return true; + } + return false; +} + +function condenseCameraLogs(cameraLogs: CameraLogs) { + // Group logs into sets based on height/width/framerate and return one log for each + // Go from this: + // [ + // { label: 'Front Camera', height: 3024, width: 4032, frameRate: 30}] + // { label: 'Back Triple Camera', height: 3024, width: 4032, frameRate: 30}] + // { label: 'Back Dual Wide Camera', height: 3024, width: 4032, frameRate: 30}] + // ] + // To this: + // [{ label: 'Front Camera, Back Triple Camera, Back Dual Wide Camera', height: 3024, width: 4032, frameRate: 30}] + const initialArray: CameraLog[] = []; + const condensedLogs = cameraLogs.reduce((accumulator, currentLog) => { + for (let i = 0; i < accumulator.length; i++) { + const recordedLog: CameraLog = accumulator[i]; + if (currentLog && logsHaveSameValuesButDifferentName(currentLog, recordedLog)) { + // Append to the label field for that log in condensed logs + const newLabel = `${recordedLog.label}, ${currentLog.label}`; + accumulator[i].label = newLabel; + return accumulator; + } + } + // Add a new log to condensed logs, when it doesn't match the existing ones + if (currentLog) { + return accumulator.concat(currentLog); + } + return accumulator; + }, initialArray); + return condensedLogs; +} + +async function logCameraInfo(trackEvent: TrackEventType) { + const devices = await navigator.mediaDevices.enumerateDevices(); + const videoDevices = devices.filter((device) => device.kind === 'videoinput'); + const cameraLogs = await Promise.all( + videoDevices.map((videoDevice) => updateConstraintsAndGetLogInfo(videoDevice, trackEvent)), + ); + const condensedCameraLogs = condenseCameraLogs(cameraLogs); + trackEvent('idv_camera_info_logged', { camera_info: condensedCameraLogs }); +} + +// This function is intended to be used only after camera permissions have been granted +// hasStartedCropping only happens after an image has been captured with the Acuant SDK, +// which means that camera permissions have been granted. +function useLogCameraInfo({ + isBackOfId, + hasStartedCropping, +}: { + isBackOfId: boolean; + hasStartedCropping: boolean; +}) { + const didLogCameraInfoRef = useRef(false); + const { trackEvent } = useContext(AnalyticsContext); + + useEffect(() => { + if (!isBackOfId) { + return; + } + if (hasStartedCropping && !didLogCameraInfoRef.current) { + logCameraInfo(trackEvent); + didLogCameraInfoRef.current = true; + } + }, [didLogCameraInfoRef, hasStartedCropping, isBackOfId, trackEvent]); +} + +export { useLogCameraInfo }; diff --git a/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts b/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts index be434df81d8..2e0baaf57d2 100644 --- a/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts +++ b/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts @@ -62,6 +62,7 @@ describe('enrollWebauthnDevice', () => { challenge, excludeCredentials, authenticatorAttachment: 'cross-platform', + hints: ['security-key'], }); expect(navigator.credentials.create).to.have.been.calledWith({ @@ -85,8 +86,9 @@ describe('enrollWebauthnDevice', () => { timeout: 800000, attestation: 'none', authenticatorSelection: { - authenticatorAttachment: 'cross-platform', userVerification: 'discouraged', + authenticatorAttachment: 'cross-platform', + hints: ['security-key'], }, excludeCredentials: [ { @@ -132,12 +134,14 @@ describe('enrollWebauthnDevice', () => { challenge, excludeCredentials, authenticatorAttachment: 'platform', + hints: ['client-device'], }); expect(navigator.credentials.create).to.have.been.calledWithMatch({ publicKey: { authenticatorSelection: { authenticatorAttachment: 'platform', + hints: ['client-device'], }, }, }); diff --git a/app/javascript/packages/webauthn/enroll-webauthn-device.ts b/app/javascript/packages/webauthn/enroll-webauthn-device.ts index ffbae3a19cf..2dae75c71d3 100644 --- a/app/javascript/packages/webauthn/enroll-webauthn-device.ts +++ b/app/javascript/packages/webauthn/enroll-webauthn-device.ts @@ -15,6 +15,8 @@ interface AuthenticatorAttestationResponseBrowserSupport getAuthenticatorData: AuthenticatorAttestationResponse['getAuthenticatorData'] | undefined; } +type PublicKeyCredentialHintType = 'client-device' | 'security-key' | 'hybrid'; + interface EnrollOptions { user: PublicKeyCredentialUserEntity; @@ -23,6 +25,8 @@ interface EnrollOptions { excludeCredentials: PublicKeyCredentialDescriptor[]; authenticatorAttachment?: AuthenticatorAttachment; + + hints?: Array; } interface EnrollResult { @@ -37,6 +41,10 @@ interface EnrollResult { transports?: string[]; } +interface AuthenticatorSelectionCriteriaWithHints extends AuthenticatorSelectionCriteria { + hints?: Array; +} + /** * All possible algorithms supported within the CBOR Object Signing and Encryption (COSE) format. * @@ -76,6 +84,7 @@ async function enrollWebauthnDevice({ challenge, excludeCredentials, authenticatorAttachment, + hints, }: EnrollOptions): Promise { const credential = (await navigator.credentials.create({ publicKey: { @@ -89,7 +98,8 @@ async function enrollWebauthnDevice({ // Prevents user from needing to use PIN with Security Key userVerification: 'discouraged', authenticatorAttachment, - }, + hints, + } as AuthenticatorSelectionCriteriaWithHints, excludeCredentials, }, })) as PublicKeyCredential; diff --git a/app/javascript/packs/webauthn-setup.ts b/app/javascript/packs/webauthn-setup.ts index 614335d8d23..743b99c827c 100644 --- a/app/javascript/packs/webauthn-setup.ts +++ b/app/javascript/packs/webauthn-setup.ts @@ -56,6 +56,7 @@ function webauthn() { .filter(Boolean), ), authenticatorAttachment: platformAuthenticator ? 'platform' : 'cross-platform', + hints: platformAuthenticator ? ['client-device', 'hybrid'] : ['security-key'], }) .then((result) => { (document.getElementById('webauthn_id') as HTMLInputElement).value = result.webauthnId; diff --git a/app/models/profile.rb b/app/models/profile.rb index c74ba71f725..3bf0af2240b 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -36,6 +36,7 @@ class Profile < ApplicationRecord legacy_unsupervised: 1, legacy_in_person: 2, unsupervised_with_selfie: 3, + in_person: 4, } attr_reader :personal_key @@ -110,6 +111,7 @@ def activate(reason_deactivated: nil) def tmx_status return nil unless IdentityConfig.store.in_person_proofing_enforce_tmx + return nil unless FeatureManagement.proofing_device_profiling_decisioning_enabled? fraud_pending_reason || :threatmetrix_pass end diff --git a/app/models/user.rb b/app/models/user.rb index 46cfa4074df..65914ca1452 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,6 +25,8 @@ class User < ApplicationRecord MAX_RECENT_EVENTS = 5 MAX_RECENT_DEVICES = 5 + BIOMETRIC_COMPARISON_IDV_LEVELS = %w[unsupervised_with_selfie in_person].to_set.freeze + enum otp_delivery_preference: { sms: 0, voice: 1 } # rubocop:disable Rails/HasManyOrHasOneDependent @@ -76,6 +78,10 @@ def confirmed? email_addresses.where.not(confirmed_at: nil).any? end + def has_gov_or_mil_email? + confirmed_email_addresses.any?(&:gov_or_mil?) + end + def accepted_rules_of_use_still_valid? if self.accepted_terms_at.present? self.accepted_terms_at > IdentityConfig.store.rules_of_use_updated_at && @@ -361,7 +367,7 @@ def identity_verified?(service_provider: nil) end def identity_verified_with_selfie? - active_profile&.idv_level == 'unsupervised_with_selfie' + BIOMETRIC_COMPARISON_IDV_LEVELS.include?(active_profile&.idv_level) end def reproof_for_irs?(service_provider:) diff --git a/app/presenters/idv/address_presenter.rb b/app/presenters/idv/address_presenter.rb index 26ca19b177d..b7c9bd17ac7 100644 --- a/app/presenters/idv/address_presenter.rb +++ b/app/presenters/idv/address_presenter.rb @@ -2,14 +2,6 @@ module Idv class AddressPresenter - def initialize(pii:) - @pii = pii - end - - def pii - @pii - end - def address_line1_hint "#{I18n.t('forms.example')} 150 Calle A Apt 3" end diff --git a/app/presenters/piv_cac_recommended_presenter.rb b/app/presenters/piv_cac_recommended_presenter.rb new file mode 100644 index 00000000000..882730987e4 --- /dev/null +++ b/app/presenters/piv_cac_recommended_presenter.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class PivCacRecommendedPresenter + attr_reader :user + def initialize(user) + @user = user + end + + def info + if MfaPolicy.new(user).two_factor_enabled? + I18n.t('two_factor_authentication.piv_cac_upsell.existing_user_info', email_type: email_type) + else + I18n.t('two_factor_authentication.piv_cac_upsell.new_user_info', email_type: email_type) + end + end + + def email_type + address = user.confirmed_email_addresses.find { |address| address.gov_or_mil? } + case address.email.end_with?('.gov') + when true + '.gov' + else + '.mil' + end + end + + def skip_text + if MfaPolicy.new(user).two_factor_enabled? + I18n.t('two_factor_authentication.piv_cac_upsell.skip') + else + I18n.t('two_factor_authentication.piv_cac_upsell.choose_other_method') + end + end +end diff --git a/app/presenters/two_factor_options_presenter.rb b/app/presenters/two_factor_options_presenter.rb index 76e8c3b361a..83a0d4434f7 100644 --- a/app/presenters/two_factor_options_presenter.rb +++ b/app/presenters/two_factor_options_presenter.rb @@ -11,6 +11,7 @@ class TwoFactorOptionsPresenter :user_agent delegate :two_factor_enabled?, to: :mfa_policy + delegate :has_gov_or_mil_email?, to: :user, prefix: :user def initialize( user_agent:, diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 3d42c776102..a7761ae27be 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -806,6 +806,20 @@ def idv_barcode_warning_retake_photos_clicked(liveness_checking_required:, **ext ) end + # @param [Hash] error + def idv_camera_info_error(error:, **_extra) + track_event(:idv_camera_info_error, error: error) + end + + # @param [String] flow_path whether the user is in the hybrid or standard flow + # @param [Array] camera_info Information on the users cameras max resolution + # as captured by the browser + def idv_camera_info_logged(flow_path:, camera_info:, **_extra) + track_event( + :idv_camera_info_logged, flow_path: flow_path, camera_info: camera_info + ) + end + # @param [String] step the step that the user was on when they clicked cancel # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components # @param [String,nil] active_profile_idv_level ID verification level of user's active profile. @@ -3162,6 +3176,34 @@ def idv_request_letter_visited( ) end + # Acuant SDK errored after loading but before initialization + # @param [Boolean] success + # @param [String] error_message + # @param [Boolean] liveness_checking_required Whether or not the selfie is required + # @param [String] acuant_version + # @param [Integer] captureAttempts number of attempts to capture / upload an image + # (previously called "attempt") + # rubocop:disable Naming/VariableName,Naming/MethodParameterName + def idv_sdk_error_before_init( + success:, + error_message:, + liveness_checking_required:, + acuant_version:, + captureAttempts: nil, + **extra + ) + track_event( + :idv_sdk_error_before_init, + success:, + error_message: error_message, + liveness_checking_required:, + acuant_version: acuant_version, + captureAttempts: captureAttempts, + **extra, + ) + end + # rubocop:enable Naming/VariableName,Naming/MethodParameterName + # User closed the SDK for taking a selfie without submitting a photo # @param [String] acuant_version # @param [Integer] captureAttempts number of attempts to capture / upload an image @@ -4401,6 +4443,21 @@ def piv_cac_login_visited track_event(:piv_cac_login_visited) end + # @param [String] action what action user made + # Tracks when user submits an action on Piv Cac recommended page + def piv_cac_recommended(action: nil, **extra) + track_event( + :piv_cac_recommended, + action: action, + **extra, + ) + end + + # Tracks when user visits piv cac recommended + def piv_cac_recommended_visited + track_event(:piv_cac_recommended_visited) + end + # @identity.idp.previous_event_name User Registration: piv cac setup visited # @identity.idp.previous_event_name PIV CAC setup visited # Tracks when user's piv cac setup diff --git a/app/services/idv/profile_maker.rb b/app/services/idv/profile_maker.rb index 982ea822513..42dd8a07b18 100644 --- a/app/services/idv/profile_maker.rb +++ b/app/services/idv/profile_maker.rb @@ -48,7 +48,12 @@ def save_profile( def set_idv_level(in_person_verification_needed:, selfie_check_performed:) if in_person_verification_needed - :legacy_in_person + if IdentityConfig.store.in_person_proofing_enforce_tmx && + FeatureManagement.proofing_device_profiling_decisioning_enabled? + :in_person + else + :legacy_in_person + end elsif FeatureManagement.idv_allow_selfie_check? && selfie_check_performed :unsupervised_with_selfie else diff --git a/app/services/idv/session.rb b/app/services/idv/session.rb index 93c464fa02e..dd89d55cb39 100644 --- a/app/services/idv/session.rb +++ b/app/services/idv/session.rb @@ -169,6 +169,16 @@ def failed_phone_step_numbers session[:failed_phone_step_params] ||= [] end + def updated_user_address=(updated_user_address) + session[:updated_user_address] = nil if updated_user_address.nil? + session[:updated_user_address] = updated_user_address.to_h + end + + def updated_user_address + return nil if session[:updated_user_address].blank? + Pii::Address.new(**session[:updated_user_address]) + end + def add_failed_phone_step_number(phone) parsed_phone = Phonelib.parse(phone) phone_e164 = parsed_phone.e164 diff --git a/app/services/pii/address.rb b/app/services/pii/address.rb new file mode 100644 index 00000000000..64517cb6d97 --- /dev/null +++ b/app/services/pii/address.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# rubocop:disable Style/MutableConstant +module Pii + Address = RedactedData.define(:state, :zipcode, :city, :address1, :address2) +end +# rubocop:enable Style/MutableConstant diff --git a/app/views/idv/address/new.html.erb b/app/views/idv/address/new.html.erb index 80358753a39..29a301e8552 100644 --- a/app/views/idv/address/new.html.erb +++ b/app/views/idv/address/new.html.erb @@ -21,7 +21,7 @@ %> <%= simple_form_for( - :idv_form, + @address_form, url: idv_address_path, method: 'POST', html: { autocomplete: 'off', class: 'margin-top-5' }, @@ -35,7 +35,6 @@ hint_html: { class: @presenter.hint_class }, required: true, maxlength: 255, - input_html: { value: @presenter.pii['address1'] }, ) %> <%= render ValidatedFieldComponent.new( form: f, @@ -45,7 +44,6 @@ hint_html: { class: @presenter.hint_class }, required: false, maxlength: 255, - input_html: { value: @presenter.pii['address2'] }, ) %> <%= render ValidatedFieldComponent.new( form: f, @@ -55,7 +53,6 @@ hint_html: { class: @presenter.hint_class }, required: true, maxlength: 255, - input_html: { value: @presenter.pii['city'] }, ) %> <%= render ValidatedFieldComponent.new( form: f, @@ -63,7 +60,6 @@ collection: us_states_territories, label: t('idv.form.state'), required: true, - selected: @presenter.pii['state'], ) %>
<%# using :tel for mobile numeric keypad %> @@ -76,7 +72,7 @@ hint_html: { class: @presenter.hint_class }, required: true, pattern: '(\d{5}([\-]\d{4})?)', - input_html: { value: @presenter.pii['zipcode'], class: 'zipcode' }, + input_html: { class: 'zipcode' }, error_messages: { patternMismatch: t('idv.errors.pattern_mismatch.zipcode'), }, diff --git a/app/views/sign_up/email_resend/new.html.erb b/app/views/sign_up/email_resend/new.html.erb deleted file mode 100644 index e81f11d76d9..00000000000 --- a/app/views/sign_up/email_resend/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -<% self.title = t('titles.confirmations.new') %> - -<%= render PageHeadingComponent.new.with_content(t('headings.confirmations.new')) %> -<%= simple_form_for( - @resend_email_confirmation_form, - url: sign_up_register_path, - html: { autocomplete: 'off', method: :post }, - ) do |f| %> - <%= render ValidatedFieldComponent.new( - form: f, - name: :email, - label: t('forms.registration.labels.email'), - required: true, - ) %> - <%= f.submit t('forms.buttons.resend_confirmation'), class: 'margin-top-2 margin-bottom-1' %> -<% end %> diff --git a/app/views/sign_up/emails/show.html.erb b/app/views/sign_up/emails/show.html.erb index be934f3b8d7..d6a85546d9c 100644 --- a/app/views/sign_up/emails/show.html.erb +++ b/app/views/sign_up/emails/show.html.erb @@ -26,9 +26,10 @@ url: sign_up_register_path do |f| %> <%= f.input :email, as: :hidden %> <%= f.input :resend, as: :hidden %> + <%= f.input :terms_accepted, as: :hidden %> <%= f.button :button, t('notices.signed_up_but_unconfirmed.resend_confirmation_email') %> <% end %> - <% end %> + <% end %> <% c.with_option( url: sign_up_email_path, ).with_content(t('notices.use_diff_email.link').upcase_first) %> diff --git a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb index f033c58e5d7..110781b1b05 100644 --- a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb +++ b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb @@ -14,7 +14,7 @@ <% end %>
- <%= render 'idv/shared/mini_logo', filename: 'logo.png' %> + <%= render 'idv/shared/mini_logo', filename: 'email/logo.png' %> <%= render BarcodeComponent.new( barcode_data: @presenter.enrollment_code, barcode_image_url: @presenter.barcode_image_url, diff --git a/app/views/users/piv_cac_recommended/show.html.erb b/app/views/users/piv_cac_recommended/show.html.erb new file mode 100644 index 00000000000..3e7ef1e0167 --- /dev/null +++ b/app/views/users/piv_cac_recommended/show.html.erb @@ -0,0 +1,33 @@ +<% self.title = t('titles.piv_cac_setup.upsell') %> + +<%= render AlertIconComponent.new(icon_name: :info_question, class: 'margin-bottom-4') %> + +<%= render PageHeadingComponent.new.with_content(t('titles.piv_cac_setup.upsell')) %> + +

+ <%= @recommended_presenter.info %> +

+ +<%= render ButtonComponent.new( + action: ->(**tag_options, &block) do + button_to( + login_piv_cac_recommended_add_path, + **tag_options, + &block + ) + end, + big: true, + class: 'margin-top-5 margin-bottom-2', + ).with_content(t('two_factor_authentication.piv_cac_upsell.add_piv')) %> + +<%= render ButtonComponent.new( + action: ->(**tag_options, &block) do + button_to( + login_piv_cac_recommended_skip_path, + **tag_options, + &block + ) + end, + unstyled: true, + ).with_content(@recommended_presenter.skip_text) %> + diff --git a/bin/setup b/bin/setup index 4a92358cb1d..6dc884c26c4 100755 --- a/bin/setup +++ b/bin/setup @@ -74,6 +74,6 @@ Dir.chdir APP_ROOT do run "make clobber_logs" puts "\n== Restarting application server ==" - run "mkdir -p tmp" + run "mkdir -p tmp/pids" run "touch tmp/restart.txt" end diff --git a/config/application.yml.default b/config/application.yml.default index 15328ec8bb2..a8ceef5f621 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -137,6 +137,7 @@ in_person_email_reminder_late_benchmark_in_days: 4 in_person_proofing_enabled: false in_person_proofing_enforce_tmx: false in_person_proofing_opt_in_enabled: false +in_person_state_id_controller_enabled: false in_person_enrollment_validity_in_days: 30 in_person_enrollments_ready_job_email_body_pattern: '\A\s*(?\d{16})\s*\Z' in_person_enrollments_ready_job_cron: '0/10 * * * *' @@ -350,7 +351,7 @@ version_headers_enabled: false vtm_url: 'https://developer.login.gov/vot-trust-framework' use_dashboard_service_providers: false use_kms: false -use_vot_in_sp_requests: false +use_vot_in_sp_requests: true usps_auth_token_refresh_job_enabled: false usps_confirmation_max_days: 30 usps_ipp_password: '' @@ -506,7 +507,6 @@ production: state_tracking_enabled: false telephony_adapter: pinpoint use_kms: true - use_vot_in_sp_requests: false usps_auth_token_refresh_job_enabled: true usps_confirmation_max_days: 30 usps_upload_sftp_directory: '' @@ -601,7 +601,6 @@ test: verify_gpo_key_max_attempts: 2 verify_personal_key_attempt_window_in_minutes: 3 verify_personal_key_max_attempts: 2 - use_vot_in_sp_requests: true usps_ipp_root_url: 'http://localhost:1000' usps_upload_sftp_directory: "/directory" usps_upload_sftp_host: example.com diff --git a/config/initializers/geocoder.rb b/config/initializers/geocoder.rb index ff4f03e8937..66c71cfafce 100644 --- a/config/initializers/geocoder.rb +++ b/config/initializers/geocoder.rb @@ -13,7 +13,7 @@ def language=(_locale); end GEO_DATA_FILEPATH = Rails.root.join(IdentityConfig.store.geo_data_file_path).freeze -if File.exist?(GEO_DATA_FILEPATH) +if File.exist?(GEO_DATA_FILEPATH) && !Rails.env.test? Geocoder.configure( ip_lookup: :geoip2, geoip2: { diff --git a/config/locales/doc_auth/en.yml b/config/locales/doc_auth/en.yml index 734145929a0..df16f91edab 100644 --- a/config/locales/doc_auth/en.yml +++ b/config/locales/doc_auth/en.yml @@ -155,12 +155,12 @@ en: information below is incorrect, please %{link_html} of your state‑issued ID. capture_scan_warning_link: upload new photos - document_capture: Add photos of your ID + document_capture: Add photos of your driver’s license or state ID card document_capture_back: Back of your ID document_capture_front: Front of your ID - document_capture_selfie: A photo of yourself + document_capture_selfie: Photo of your face document_capture_subheader_id: Driver’s license or state ID card - document_capture_subheader_selfie: Photo of yourself + document_capture_subheader_selfie: Photo of your face document_capture_with_selfie: Add photos of your ID and a photo of yourself front: Front of your driver’s license or state ID how_to_verify: Choose how you want to verify your identity @@ -171,7 +171,7 @@ en: no_ssn: Don’t have a Social Security number? review_issues: Check your images and try again secure_account: Secure your account - selfie: Photo + selfie: Photo of your face ssn: Enter your Social Security number ssn_update: Update your Social Security number text_message: We sent a message to your phone @@ -229,6 +229,7 @@ en: secure_account: We’ll encrypt your account when you re-enter your password. Encryption means your data is protected and only you will be able to access or change your information. + selfie_capture_content: We’ll check that you are the person on your ID. selfie_capture_status: face_close_to_border: Too close to the frame face_not_found: Face not found @@ -280,15 +281,17 @@ en: text4: Your password saves and encrypts your personal information. tips: document_capture_hint: Must be a JPG or PNG - document_capture_id_text1: Use a dark background - document_capture_id_text2: Take the photo on a flat surface - document_capture_id_text3: Do not use the flash on your camera - document_capture_id_text4: File size should be at least 2 MB - document_capture_selfie_id_header_text: Tips for taking clear photos - document_capture_selfie_selfie_text: Tips for taking a clear photo - document_capture_selfie_text1: Hold your device at eye level - document_capture_selfie_text2: Make sure your whole face is visible - document_capture_selfie_text3: Take your photo in a well-lit place + document_capture_id_text1: Place your ID on a flat and dark surface. + document_capture_id_text2: Take your photo in a well-lit place. + document_capture_id_text3: Avoid glare or shadows on your ID. + document_capture_id_text4: File size should be at least 2 MB. + document_capture_selfie_id_header_text: How to take clear photos of your ID + document_capture_selfie_selfie_text: How to prepare for your photo + document_capture_selfie_text1: Remove any clothing items or accessories that + might cover your face. We suggest removing your glasses or hat. + document_capture_selfie_text2: Take your photo in a well-lit place. + document_capture_selfie_text3: Keep your expression neutral. + document_capture_selfie_text4: Make sure your whole face is visible within the green circle. review_issues_id_header_text: 'Review the images of your state‑issued ID:' review_issues_id_text1: Did you use a dark background? review_issues_id_text2: Did you take the photo on a flat surface? diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml index c6d05cc9a55..9dfdbcd0f6e 100644 --- a/config/locales/doc_auth/es.yml +++ b/config/locales/doc_auth/es.yml @@ -186,13 +186,14 @@ es: información que aparece a continuación es incorrecta, por favor, %{link_html} de su ID emitido por el estado. capture_scan_warning_link: suba nuevas fotos - document_capture: Incluir fotos de su identificación - document_capture_back: Parte trasera de su documento de identidad - document_capture_front: Parte delantera de su documento de identidad - document_capture_selfie: Una foto tuya - document_capture_subheader_id: Licencia de conducir o con un documento de identidad estatal - document_capture_subheader_selfie: Foto suya - document_capture_with_selfie: Incluir fotos de su identificación y una foto suya + document_capture: Añade fotos de tu licencia de conducir o credencial de + identificación oficial + document_capture_back: Reverso de su identificación + document_capture_front: Frente de su identificación + document_capture_selfie: Fotografía de su cara + document_capture_subheader_id: Licencia de conducir o tarjeta de identificación estatal + document_capture_subheader_selfie: Fotografía de su cara + document_capture_with_selfie: Agregue las fotos de su identificación y una foto de usted front: Anverso de su licencia de conducir o identificación estatal how_to_verify: Elija cómo quiere verificar su identidad hybrid_handoff: '¿Cómo desea añadir su documento de identidad?' @@ -202,7 +203,7 @@ es: no_ssn: ¿No tiene un número de Seguro Social? review_issues: Revise sus imágenes e inténtelo de nuevo secure_account: Asegure su cuenta - selfie: Foto + selfie: Fotografía de su cara ssn: Ingrese su número de Seguro Social ssn_update: Actualice su número de Seguro Social text_message: Enviamos un mensaje a su teléfono @@ -268,6 +269,7 @@ es: secure_account: Cifraremos su cuenta cuando vuelva a introducir su contraseña. La encriptación significa que sus datos están protegidos y solo usted podrá acceder o modificar su información. + selfie_capture_content: Revisaremos que usted sea la persona que figura en su identificación. selfie_capture_status: face_close_to_border: Demasiado cerca del marco face_not_found: No se detectó el rostro @@ -326,15 +328,17 @@ es: text4: Tu contraseña permitirá guardar y encriptar tu información personal. tips: document_capture_hint: Debe ser un JPG o PNG - document_capture_id_text1: Use un fondo oscuro - document_capture_id_text2: Tome la foto en una superficie plana - document_capture_id_text3: No use el flash de su cámara - document_capture_id_text4: El tamaño del archivo debe ser de al menos 2 MB - document_capture_selfie_id_header_text: Consejos para obtener fotografías nítidas - document_capture_selfie_selfie_text: Consejos para obtener una foto nítidas - document_capture_selfie_text1: Mantenga el dispositivo al mismo nivel que los ojos - document_capture_selfie_text2: Asegúrate de que tu rostro completo sea visible - document_capture_selfie_text3: Tómese la foto en un sitio con buena iluminación + document_capture_id_text1: Coloque su identificación en una superficie plana y de color oscuro. + document_capture_id_text2: Tómese la foto en un lugar bien iluminado. + document_capture_id_text3: Evite que se vean reflejos o sombras en su identificación. + document_capture_id_text4: El tamaño del archivo debe ser de al menos 2 MB. + document_capture_selfie_id_header_text: Cómo tomar fotos nítidas de su identificación + document_capture_selfie_selfie_text: Cómo prepararse para tomar su foto + document_capture_selfie_text1: Quite cualquier prenda o accesorio que pueda + cubrirle la cara. Sugerimos que se quite los anteojos o el sombrero. + document_capture_selfie_text2: Tómese la foto en un lugar bien iluminado. + document_capture_selfie_text3: Mantenga una expresión neutral. + document_capture_selfie_text4: Revise que se vea su rostro completo dentro del círculo verde. review_issues_id_header_text: 'Revise las imágenes de su documento de identidad expedido por el estado:' review_issues_id_text1: '¿Ha usado un fondo oscuro?' diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml index 30b9e236d0c..5928916521e 100644 --- a/config/locales/doc_auth/fr.yml +++ b/config/locales/doc_auth/fr.yml @@ -196,13 +196,14 @@ fr: pièce d’identité. Si les informations ci-dessous sont incorrectes, veuillez %{link_html} de votre carte d’identité délivrée par l’État. capture_scan_warning_link: télécharger de nouvelles photos - document_capture: Ajoutez des photos de votre pièce d’identité - document_capture_back: Verso de votre carte d’identité - document_capture_front: Recto de votre carte d’identité - document_capture_selfie: Une photo de vous - document_capture_subheader_id: Permis de conduire ou de carte d’identité d’État - document_capture_subheader_selfie: Photo de vous-même - document_capture_with_selfie: Ajoutez des photos de votre pièce d’identité et une photo de vous-même + document_capture: Ajoutez des photos de votre permis de conduire ou de votre + carte d’identité nationale + document_capture_back: Verso de votre pièce d’identité + document_capture_front: Recto de votre pièce d’identité + document_capture_selfie: Photo de votre visage + document_capture_subheader_id: Permis de conduire ou carte d’identité d’un État + document_capture_subheader_selfie: Photo de votre visage + document_capture_with_selfie: Ajouter des photos de votre pièce d’identité et une photo de vous-même front: Recto de votre permis de conduire ou de votre carte d’identité de l’État how_to_verify: Choisissez la manière dont vous souhaitez confirmer votre identité hybrid_handoff: Comment voulez-vous ajouter votre identifiant ? @@ -212,7 +213,7 @@ fr: no_ssn: Vous n’avez pas de numéro de sécurité sociale? review_issues: Vérifiez vos images et essayez à nouveau secure_account: Sécuriser votre compte - selfie: Photo + selfie: Photo de votre visage ssn: Saisissez votre numéro de sécurité sociale ssn_update: Mettre à jour votre numéro de Sécurité Sociale text_message: Nous avons envoyé un message à votre téléphone @@ -280,6 +281,8 @@ fr: votre mot de passe. Le chiffrage signifie que vos données sont protégées et que vous êtes le/la seul(e) à pouvoir accéder à vos informations ou les modifier. + selfie_capture_content: Nous vérifierons que vous êtes la personne figurant sur + la pièce d’identité. selfie_capture_status: face_close_to_border: Trop près du cadre face_not_found: Visage non trouvé @@ -338,15 +341,19 @@ fr: text4: Votre mot de passe enregistre et crypte vos informations personnelles. tips: document_capture_hint: Doit être un JPG ou PNG - document_capture_id_text1: Utilisez un fond sombre - document_capture_id_text2: Prenez la photo sur une surface plane - document_capture_id_text3: N’utilisez pas le flash de votre appareil photo - document_capture_id_text4: La taille du fichier doit être d’au moins 2 Mo - document_capture_selfie_id_header_text: Conseils pour prendre des photos claires - document_capture_selfie_selfie_text: Conseils pour prendre un photo claires - document_capture_selfie_text1: Tenez votre appareil à hauteur des yeux - document_capture_selfie_text2: Veillez à ce que l’ensemble de votre visage soit visible - document_capture_selfie_text3: Prenez votre photo dans un endroit bien éclairé + document_capture_id_text1: Placez votre pièce d’identité sur une surface plane et sombre. + document_capture_id_text2: Prenez votre photo dans un endroit bien éclairé. + document_capture_id_text3: Évitez les reflets et les ombres sur votre pièce d’identité. + document_capture_id_text4: La taille du fichier doit être d’au moins 2 Mo. + document_capture_selfie_id_header_text: Comment prendre des photos nettes de votre pièce d’identité + document_capture_selfie_selfie_text: Comment vous préparer pour prendre la photo de vous-même + document_capture_selfie_text1: Retirez tous articles ou accessoires + vestimentaires susceptibles de cacher votre visage. Nous vous + conseillons de retirer vos lunettes ou votre couvre-chef. + document_capture_selfie_text2: Prenez votre photo dans un endroit bien éclairé. + document_capture_selfie_text3: Gardez une expression neutre. + document_capture_selfie_text4: Assurez-vous que l’ensemble de votre visage soit + visible à l’intérieur du cercle vert. review_issues_id_header_text: 'Examinez les images de votre carte d’identité délivrée par l’État:' review_issues_id_text1: Avez-vous utilisé un fond sombre? review_issues_id_text2: Avez-vous pris la photo sur une surface plane? diff --git a/config/locales/forms/en.yml b/config/locales/forms/en.yml index 750fb790f5c..3f8038ec6ae 100644 --- a/config/locales/forms/en.yml +++ b/config/locales/forms/en.yml @@ -37,7 +37,6 @@ en: disable: Delete edit: Edit manage: Manage - resend_confirmation: Resend confirmation instructions send_link: Send link send_one_time_code: Send code submit: diff --git a/config/locales/forms/es.yml b/config/locales/forms/es.yml index 5530b4377f4..84994051f13 100644 --- a/config/locales/forms/es.yml +++ b/config/locales/forms/es.yml @@ -40,7 +40,6 @@ es: disable: Borrar edit: Editar manage: Administrar - resend_confirmation: Reenviar instrucciones de confirmación send_link: Enviar enlace send_one_time_code: Enviar código submit: diff --git a/config/locales/forms/fr.yml b/config/locales/forms/fr.yml index d701464683e..d52bf4b5cef 100644 --- a/config/locales/forms/fr.yml +++ b/config/locales/forms/fr.yml @@ -41,7 +41,6 @@ fr: disable: Effacer edit: Modifier manage: Administrer - resend_confirmation: Envoyer les instructions de confirmation de nouveau send_link: Envoyer le lien send_one_time_code: Envoyer le code submit: diff --git a/config/locales/headings/en.yml b/config/locales/headings/en.yml index 92bb4db275b..89dad46edc7 100644 --- a/config/locales/headings/en.yml +++ b/config/locales/headings/en.yml @@ -19,8 +19,6 @@ en: phone: Add a phone number cancellations: prompt: Are you sure you want to cancel? - confirmations: - new: Send another confirmation email create_account_new_users: Create an account for new users create_account_with_sp: sp_text: is using %{app_name} to allow you to sign in to your account safely and diff --git a/config/locales/headings/es.yml b/config/locales/headings/es.yml index e951e3ab7af..2e35e947912 100644 --- a/config/locales/headings/es.yml +++ b/config/locales/headings/es.yml @@ -19,8 +19,6 @@ es: phone: Agregar un número de teléfono cancellations: prompt: '¿Estas seguro que quieres cancelar?' - confirmations: - new: Enviar otro email de confirmación create_account_new_users: Crear una cuenta para usuarios nuevos create_account_with_sp: sp_text: está utilizando %{app_name} para permitirle iniciar sesión en su cuenta diff --git a/config/locales/headings/fr.yml b/config/locales/headings/fr.yml index d59540f0ce9..ad3f2805718 100644 --- a/config/locales/headings/fr.yml +++ b/config/locales/headings/fr.yml @@ -19,8 +19,6 @@ fr: phone: Ajouter un numéro de téléphone cancellations: prompt: Es-tu sûre de vouloir annuler? - confirmations: - new: Envoyer un autre courriel de confirmation create_account_new_users: Créer un compte pour les nouveaux utilisateurs create_account_with_sp: sp_text: utilise %{app_name} pour vous permettre de vous connecter à votre diff --git a/config/locales/titles/en.yml b/config/locales/titles/en.yml index 1cb3c13fa70..e960b51410e 100644 --- a/config/locales/titles/en.yml +++ b/config/locales/titles/en.yml @@ -8,7 +8,6 @@ en: backup_codes: Don’t lose your backup codes confirmations: delete: Please confirm - new: Resend confirmation instructions for your account show: Choose a password doc_auth: address: Update your mailing address @@ -59,6 +58,7 @@ en: new: Use your PIV/CAC to sign in to your account piv_cac_setup: new: Use your PIV/CAC card to secure your account + upsell: Enhance your account security with a government employee ID present_piv_cac: Present your PIV/CAC present_webauthn: Connect your hardware security key reactivate_account: Reactivate your account diff --git a/config/locales/titles/es.yml b/config/locales/titles/es.yml index d2db4d2eebc..11b409ab388 100644 --- a/config/locales/titles/es.yml +++ b/config/locales/titles/es.yml @@ -8,7 +8,6 @@ es: backup_codes: No pierda sus códigos de respaldo confirmations: delete: Por favor confirmar - new: Reenviar instrucciones de confirmación de su cuenta show: Elija una contraseña doc_auth: address: Actualice su dirección postal @@ -59,6 +58,8 @@ es: new: Use su PIV / CAC para iniciar sesión en su cuenta piv_cac_setup: new: Use su tarjeta PIV/CAC para asegurar su cuenta + upsell: Aumente la seguridad de su cuenta con una identificación de empleado del + gobierno. present_piv_cac: Presenta tu PIV/CAC present_webauthn: Conecte su clave de seguridad de hardware reactivate_account: Reactive su cuenta diff --git a/config/locales/titles/fr.yml b/config/locales/titles/fr.yml index 3af1c90e41d..93940a033d3 100644 --- a/config/locales/titles/fr.yml +++ b/config/locales/titles/fr.yml @@ -8,7 +8,6 @@ fr: backup_codes: Ne perdez pas vos codes de sauvegarde confirmations: delete: Veuillez confirmer - new: Envoyer les instructions de confirmation pour votre compte show: Choisissez un mot de passe doc_auth: address: Mettez à jour votre adresse postale @@ -59,6 +58,7 @@ fr: new: Utilisez votre PIV / CAC pour vous connecter à votre compte piv_cac_setup: new: Utilisez votre carte PIV/CAC pour sécuriser votre compte + upsell: Renforcer la sécurité de votre compte avec une carte d’employé fédéral present_piv_cac: Veuillez présenter votre carte PIV/CAC present_webauthn: Branchez votre clé de sécurité physique reactivate_account: Réactiver le profil diff --git a/config/locales/two_factor_authentication/en.yml b/config/locales/two_factor_authentication/en.yml index 674be3a1555..0b039cdf1d0 100644 --- a/config/locales/two_factor_authentication/en.yml +++ b/config/locales/two_factor_authentication/en.yml @@ -146,6 +146,16 @@ en: nickname: Nickname renamed: Successfully renamed your PIV/CAC method piv_cac_header_text: Present your PIV/CAC + piv_cac_upsell: + add_piv: Add PIV/CAC card + choose_other_method: Choose other methods instead + existing_user_info: Because you are using a %{email_type} email, we recommend + you add your government employee ID as one of your authentication + methods. This will greatly enhance your account security. + new_user_info: Because you are using a %{email_type} email, we recommend you add + your government employee ID as one of your authentication methods. This + adds another layer of security to your account. + skip: Skip please_try_again_html: Please try again in %{countdown}. read_about_two_factor_authentication: Read about two-factor authentication recaptcha: diff --git a/config/locales/two_factor_authentication/es.yml b/config/locales/two_factor_authentication/es.yml index 6b9e368f708..ffd4f5d0c6b 100644 --- a/config/locales/two_factor_authentication/es.yml +++ b/config/locales/two_factor_authentication/es.yml @@ -153,6 +153,18 @@ es: nickname: Apodo renamed: Se ha cambiado correctamente el nombre de su método PIV/CAC piv_cac_header_text: Presenta tu PIV/CAC + piv_cac_upsell: + add_piv: Agregar tarjeta PIV/CAC + choose_other_method: Elegir otros métodos + existing_user_info: Dado que utiliza un correo electrónico %{email_type}, le + recomendamos que añada su identificación de empleado del gobierno como + uno de sus métodos de autenticación. Esto aumentará en gran medida la + seguridad de su cuenta. + new_user_info: Dado que utiliza un correo electrónico %{email_type}, le + recomendamos que añada su identificación de empleado del gobierno como + uno de sus métodos de autenticación. Esto agrega un nivel adicional de + seguridad a su cuenta. + skip: Omitir please_try_again_html: Inténtelo de nuevo en %{countdown}. read_about_two_factor_authentication: Conozca la autenticación de dos factores recaptcha: diff --git a/config/locales/two_factor_authentication/fr.yml b/config/locales/two_factor_authentication/fr.yml index 2c6de307f79..b4876271f24 100644 --- a/config/locales/two_factor_authentication/fr.yml +++ b/config/locales/two_factor_authentication/fr.yml @@ -161,6 +161,18 @@ fr: nickname: Pseudo renamed: Votre méthode PIV/CAC a été renommée avec succès piv_cac_header_text: Veuillez présenter votre carte PIV/CAC + piv_cac_upsell: + add_piv: Ajouter une carte PIV/CAC + choose_other_method: Choisir plutôt d’autres méthodes + existing_user_info: Comme vous utilisez une adresse e-mail avec le suffixe + %{email_type}, nous vous recommandons d’ajouter votre carte d’employé + fédéral parmi vos méthodes d’authentification. Ceci renforcera + considérablement la sécurité de votre compte. + new_user_info: Comme vous utilisez une adresse e-mail avec le suffixe + %{email_type}, nous vous recommandons d’ajouter votre carte d’employé + fédéral parmi vos méthodes d’authentification. Ceci permet d’ajouter une + couche supplémentaire de sécurité à votre compte. + skip: Ignorer please_try_again_html: Veuillez essayer de nouveau dans %{countdown}. read_about_two_factor_authentication: En savoir plus sur l’authentification à deux facteurs recaptcha: diff --git a/config/routes.rb b/config/routes.rb index 9a443c0028b..f37a9283f3a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -144,6 +144,9 @@ post 'login/add_piv_cac/prompt' => 'users/piv_cac_setup_from_sign_in#decline' get 'login/add_piv_cac/success' => 'users/piv_cac_setup_from_sign_in#success' post 'login/add_piv_cac/success' => 'users/piv_cac_setup_from_sign_in#next' + get 'login/piv_cac_recommended' => 'users/piv_cac_recommended#show' + post 'login/piv_cac_recommended/add' => 'users/piv_cac_recommended#confirm' + post 'login/piv_cac_recommended/skip' => 'users/piv_cac_recommended#skip' end if IdentityConfig.store.enable_test_routes @@ -297,7 +300,7 @@ as: :sign_up_create_email_confirmation get '/sign_up/enter_email' => 'sign_up/registrations#new', as: :sign_up_email post '/sign_up/enter_email' => 'sign_up/registrations#create', as: :sign_up_register - get '/sign_up/enter_email/resend' => 'sign_up/email_resend#new', as: :sign_up_email_resend + get '/sign_up/enter_email/resend' => redirect('/sign_up/enter_email') get '/sign_up/enter_password' => 'sign_up/passwords#new' get '/sign_up/verify_email' => 'sign_up/emails#show', as: :sign_up_verify_email get '/sign_up/completed' => 'sign_up/completions#show', as: :sign_up_completed diff --git a/lib/identity_config.rb b/lib/identity_config.rb index acc957aed31..9262df67825 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -268,6 +268,7 @@ def self.build_store(config_map) config.add(:in_person_public_address_search_enabled, type: :boolean) config.add(:in_person_results_delay_in_hours, type: :integer) config.add(:in_person_send_proofing_notifications_enabled, type: :boolean) + config.add(:in_person_state_id_controller_enabled, type: :boolean) config.add(:in_person_stop_expiring_enrollments, type: :boolean) config.add(:include_slo_in_saml_metadata, type: :boolean) config.add(:invalid_gpo_confirmation_zipcode, type: :string) diff --git a/lib/mailable.rb b/lib/mailable.rb index eb4707772d9..bc72e2a9142 100644 --- a/lib/mailable.rb +++ b/lib/mailable.rb @@ -13,6 +13,6 @@ def email_with_name(email, name) end def attach_images - attachments.inline['logo.png'] = File.read('app/assets/images/logo.png') + attachments.inline['logo.png'] = File.read('app/assets/images/email/logo.png') end end diff --git a/public/acuant/11.9.2/AcuantPassiveLiveness.min.js b/public/acuant/11.9.2/AcuantPassiveLiveness.min.js index 02345fb3037..0b5e602e3ec 100644 --- a/public/acuant/11.9.2/AcuantPassiveLiveness.min.js +++ b/public/acuant/11.9.2/AcuantPassiveLiveness.min.js @@ -231,7 +231,7 @@ var fq=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?a * limitations under the License. * ============================================================================= */ -/** @license See the LICENSE file. */(e,{width:this.videoElement.videoWidth,height:this.videoElement.videoHeight}),n=new hq,r=this.checkNumberFaces(t);return n.FACE_NOT_FOUND=!r&&0===t.length,n.TOO_MANY_FACES=!r&&t.length>this.MAX_NUMBER_FACES,r&&(wq&&(n.FACE_ANGLE_TOO_LARGE=!this.checkHeadRotation(t)),n.PROBABILITY_TOO_SMALL=!this.checkProbability(t),n.FACE_TOO_SMALL=!this.checkFaceSize(t),n.FACE_CLOSE_TO_BORDER=!this.checkFaceIndent(t)),n}autoCapturing(){kq.debug&&console.info(this.counterSuccessfulResults),this.counterSuccessfulResults>=this.DEFAULT_NUMBER_SUCCESSFUL_RESULTS_FOR_AUTO_CAPTURING&&(this.stream.autoCapturing(),this.counterSuccessfulResults=0)}checkNumberFaces(e){return e.length===this.MAX_NUMBER_FACES}checkProbability(e){return e[0].detection.score>+this.probabilityThreshold/100}checkFaceSize(e){const t=e[0].detection.box,{width:n,height:r,area:a}=t,{imageHeight:s,imageWidth:i}=e[0].detection,o=100/(s*i/a);return Math.min(n/this.videoRatio,r/this.videoRatio)>(this.isMobile?this.MIN_FACE_SIZE_FOR_MOBILE:this.MIN_FACE_SIZE_FOR_DESKTOP)&&o>(this.isMobile?this.MIN_OCCUPIED_SPACE_FOR_MOBILE:this.MIN_OCCUPIED_SPACE_FOR_DESKTOP)}checkFaceIndent(e){const t=e[0].detection.box,{imageHeight:n,imageWidth:r}=e[0].detection,{top:a,left:s,bottom:i,right:o}=t,u=s,l=r-o,c=n-i;return!(athis.MAX_ANGLE_TURN_HEAD||-1*a[2]>this.MAX_ANGLE_TURN_HEAD?this.headTurnCounter++:(this.counterSuccessfulHeadTurns++,this.counterSuccessfulHeadTurns>=5&&(this.headTurnCounter=0,this.counterSuccessfulHeadTurns=0)),this.headTurnCounter<=1}drawFaces(e){this.innerCanvas||this.createCanvasForDrawingMask(this.videoElement);const t=this.innerCanvas;if(!t)return console.error("no canvas for drawing");const n=t.getContext("2d");if(n){n.clearRect(0,0,t.width,t.height),n.font='small-caps 20px "Segoe UI"',n.fillStyle="white";for(const t of e){n.lineWidth=3,n.strokeStyle="deepskyblue",n.fillStyle="deepskyblue",n.globalAlpha=.6,n.beginPath(),n.rect(t.detection.box.x,t.detection.box.y,t.detection.box.width,t.detection.box.height),n.stroke(),n.globalAlpha=1,n.globalAlpha=.8,n.fillStyle="lightblue";const e=2;for(let r=0;r"+d("B",e.length),e)}function a(e){return h(">"+d("H",e.length),e)}function s(e){return h(">"+d("L",e.length),e)}function i(e,t,n){var i,o,u,l,c="",p="";if("Byte"==t)(i=e.length)<=4?p=r(e)+d("\0",4-i):(p=h(">L",[n]),c=r(e));else if("Short"==t)(i=e.length)<=2?p=a(e)+d("\0\0",2-i):(p=h(">L",[n]),c=a(e));else if("Long"==t)(i=e.length)<=1?p=s(e):(p=h(">L",[n]),c=s(e));else if("Ascii"==t)(i=(o=e+"\0").length)>4?(p=h(">L",[n]),c=o):p=o+d("\0",4-i);else if("Rational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">L",[u])+h(">L",[l]);else{i=e.length,o="";for(var f=0;fL",[u])+h(">L",[l])}p=h(">L",[n]),c=o}else if("SRational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">l",[u])+h(">l",[l]);else{i=e.length,o="";for(f=0;fl",[u])+h(">l",[l])}p=h(">L",[n]),c=o}else"Undefined"==t&&((i=e.length)>4?(p=h(">L",[n]),c=e):p=e+d("\0",4-i));return[h(">L",[i]),p,c]}function o(e,t,n){var r,a=Object.keys(e).length,s=h(">H",[a]);r=["0th","1st"].indexOf(t)>-1?2+12*a+4:2+12*a;var o="",u="";for(var l in e)if("string"==typeof l&&(l=parseInt(l)),!("0th"==t&&[34665,34853].indexOf(l)>-1||"Exif"==t&&40965==l||"1st"==t&&[513,514].indexOf(l)>-1)){var c=e[l],p=h(">H",[l]),d=g[t][l].type,f=h(">H",[m[d]]);"number"==typeof c&&(c=[c]);var y=i(c,d,8+r+n+u.length);o+=p+f+y[0]+y[1],u+=y[2]}return[s+o,u]}function u(e){var t;if("ÿØ"==e.slice(0,2))t=function(e){for(var t,n=0;n-1)this.tiftag=e;else{if("Exif"!=e.slice(0,4))throw new Error("Given file is neither JPEG nor TIFF.");this.tiftag=e.slice(6)}}if(n.version="1.0.4",n.remove=function(e){var t=!1;if("ÿØ"==e.slice(0,2));else{if("data:image/jpeg;base64,"!=e.slice(0,23)&&"data:image/jpg;base64,"!=e.slice(0,22))throw new Error("Given data is not jpeg.");e=c(e.split(",")[1]),t=!0}var n=f(e).filter((function(e){return!("ÿá"==e.slice(0,2)&&"Exif\0\0"==e.slice(4,10))})).join("");return t&&(n="data:image/jpeg;base64,"+l(n)),n},n.insert=function(e,t){var n=!1;if("Exif\0\0"!=e.slice(0,6))throw new Error("Given data is not exif.");if("ÿØ"==t.slice(0,2));else{if("data:image/jpeg;base64,"!=t.slice(0,23)&&"data:image/jpg;base64,"!=t.slice(0,22))throw new Error("Given data is not jpeg.");t=c(t.split(",")[1]),n=!0}var r="ÿá"+h(">H",[e.length+2])+e,a=function(e,t){var n=!1,r=[];e.forEach((function(a,s){"ÿá"==a.slice(0,2)&&"Exif\0\0"==a.slice(4,10)&&(n?r.unshift(s):(e[s]=t,n=!0))})),r.forEach((function(t){e.splice(t,1)})),!n&&t&&(e=[e[0],t].concat(e.slice(1)));return e.join("")}(f(t),r);return n&&(a="data:image/jpeg;base64,"+l(a)),a},n.load=function(e){var t;if("string"!=typeof e)throw new Error("'load' gots invalid type argument.");if("ÿØ"==e.slice(0,2))t=e;else if("data:image/jpeg;base64,"==e.slice(0,23)||"data:image/jpg;base64,"==e.slice(0,22))t=c(e.split(",")[1]);else{if("Exif"!=e.slice(0,4))throw new Error("'load' gots invalid file data.");t=e.slice(6)}var n={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null},r=new u(t);if(null===r.tiftag)return n;"II"==r.tiftag.slice(0,2)?r.endian_mark="<":r.endian_mark=">";var a=p(r.endian_mark+"L",r.tiftag.slice(4,8))[0];n["0th"]=r.get_ifd(a,"0th");var s=n["0th"].first_ifd_pointer;if(delete n["0th"].first_ifd_pointer,34665 in n["0th"]&&(a=n["0th"][34665],n.Exif=r.get_ifd(a,"Exif")),34853 in n["0th"]&&(a=n["0th"][34853],n.GPS=r.get_ifd(a,"GPS")),40965 in n.Exif&&(a=n.Exif[40965],n.Interop=r.get_ifd(a,"Interop")),"\0\0\0\0"!=s&&(a=p(r.endian_mark+"L",s)[0],n["1st"]=r.get_ifd(a,"1st"),513 in n["1st"]&&514 in n["1st"])){var i=n["1st"][513]+n["1st"][514],o=r.tiftag.slice(n["1st"][513],i);n.thumbnail=o}return n},n.dump=function(e){var t,r,a,s,i,u,l=(t=e,JSON.parse(JSON.stringify(t))),c=!1,p=!1,d=!1,g=!1;r="0th"in l?l["0th"]:{},"Exif"in l&&Object.keys(l.Exif).length||"Interop"in l&&Object.keys(l.Interop).length?(r[34665]=1,c=!0,a=l.Exif,"Interop"in l&&Object.keys(l.Interop).length?(a[40965]=1,d=!0,s=l.Interop):Object.keys(a).indexOf(n.ExifIFD.InteroperabilityTag.toString())>-1&&delete a[40965]):Object.keys(r).indexOf(n.ImageIFD.ExifTag.toString())>-1&&delete r[34665],"GPS"in l&&Object.keys(l.GPS).length?(r[n.ImageIFD.GPSTag]=1,p=!0,i=l.GPS):Object.keys(r).indexOf(n.ImageIFD.GPSTag.toString())>-1&&delete r[n.ImageIFD.GPSTag],"1st"in l&&"thumbnail"in l&&null!=l.thumbnail&&(g=!0,l["1st"][513]=1,l["1st"][514]=1,u=l["1st"]);var y,b,v,x=o(r,"0th",0),w=x[0].length+12*c+12*p+4+x[1].length,k="",S=0,I="",A=0,E="",N=0,C="";(c&&(S=(y=o(a,"Exif",w))[0].length+12*d+y[1].length),p&&(A=(I=o(i,"GPS",w+S).join("")).length),d)&&(N=(E=o(s,"Interop",w+S+A).join("")).length);if(g&&(b=o(u,"1st",w+S+A+N),(v=function(e){var t=f(e);for(;"ÿà"<=t[1].slice(0,2)&&t[1].slice(0,2)<="ÿï";)t=[t[0]].concat(t.slice(2));return t.join("")}(l.thumbnail)).length>64e3))throw new Error("Given thumbnail is too large. max 64kB");var T="",R="",_="",F="\0\0\0\0";if(c){var M=h(">L",[D=8+w]);T=h(">H",[34665])+h(">H",[m.Long])+h(">L",[1])+M}if(p){M=h(">L",[D=8+w+S]);R=h(">H",[34853])+h(">H",[m.Long])+h(">L",[1])+M}if(d){M=h(">L",[D=8+w+S+A]);_=h(">H",[40965])+h(">H",[m.Long])+h(">L",[1])+M}if(g){var D;F=h(">L",[D=8+w+S+A+N]);var O="\0\0\0\0"+h(">L",[D+b[0].length+24+4+b[1].length]),L="\0\0\0\0"+h(">L",[v.length]);C=b[0]+O+L+"\0\0\0\0"+b[1]+v}var P=x[0]+T+R+F+x[1];return c&&(k=y[0]+_+y[1]),"Exif\0\0MM\0*\0\0\0\b"+P+k+I+E+C},u.prototype={get_ifd:function(e,t){var n,r={},a=p(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],s=e+2;n=["0th","1st"].indexOf(t)>-1?"Image":t;for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("B",a),this.tiftag.slice(t,t+a))):n=p(this.endian_mark+d("B",a),s.slice(0,a));else if(2==r)a>4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a-1)):n=s.slice(0,a-1);else if(3==r)a>2?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("H",a),this.tiftag.slice(t,t+2*a))):n=p(this.endian_mark+d("H",a),s.slice(0,2*a));else if(4==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("L",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("L",a),s);else if(5==r)if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a)):n=s.slice(0,a);else if(9==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("l",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("l",a),s);else{if(10!=r)throw new Error("Exif might be wrong. Got incorrect value type to decode. type:"+r);if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(i=0;i>2,s=(3&t)<<4|(n=e.charCodeAt(l++))>>4,i=(15&n)<<2|(r=e.charCodeAt(l++))>>6,o=63&r,isNaN(n)?i=o=64:isNaN(r)&&(o=64),u=u+c.charAt(a)+c.charAt(s)+c.charAt(i)+c.charAt(o);return u};if("undefined"!=typeof window&&"function"==typeof window.atob)var c=window.atob;if(void 0===c)c=function(e){var t,n,r,a,s,i,o="",u=0,l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");u>4,n=(15&a)<<4|(s=l.indexOf(e.charAt(u++)))>>2,r=(3&s)<<6|(i=l.indexOf(e.charAt(u++))),o+=String.fromCharCode(t),64!=s&&(o+=String.fromCharCode(n)),64!=i&&(o+=String.fromCharCode(r));return o};function h(e,t){if(!(t instanceof Array))throw new Error("'pack' error. Got invalid type argument.");if(e.length-1!=t.length)throw new Error("'pack' error. "+(e.length-1)+" marks, "+t.length+" elements.");var n;if("<"==e[0])n=!0;else{if(">"!=e[0])throw new Error("");n=!1}for(var r="",a=1,s=null,i=null,o=null;i=e[a];){if("b"==i.toLowerCase()){if(s=t[a-1],"b"==i&&s<0&&(s+=256),s>255||s<0)throw new Error("'pack' error.");o=String.fromCharCode(s)}else if("H"==i){if((s=t[a-1])>65535||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}else{if("l"!=i.toLowerCase())throw new Error("'pack' error.");if(s=t[a-1],"l"==i&&s<0&&(s+=4294967296),s>4294967295||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s/16777216))+String.fromCharCode(Math.floor(s%16777216/65536))+String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}r+=o,a+=1}return r}function p(e,t){if("string"!=typeof t)throw new Error("'unpack' error. Got invalid type argument.");for(var n,r=0,a=1;a"!=e[0])throw new Error("'unpack' error.");n=!1}for(var s=[],i=0,o=1,u=null,l=null,c=null,h="";l=e[o];){if("b"==l.toLowerCase())c=1,u=(h=t.slice(i,i+c)).charCodeAt(0),"b"==l&&u>=128&&(u-=256);else if("H"==l)c=2,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=256*h.charCodeAt(0)+h.charCodeAt(1);else{if("l"!=l.toLowerCase())throw new Error("'unpack' error. "+l);c=4,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=16777216*h.charCodeAt(0)+65536*h.charCodeAt(1)+256*h.charCodeAt(2)+h.charCodeAt(3),"l"==l&&u>=2147483648&&(u-=4294967296)}s.push(u),i+=c,o+=1}return s}function d(e,t){for(var n="",r=0;rH",e.slice(t+2,t+4))[0]+2;if(n.push(e.slice(t,r)),(t=r)>=e.length)throw new Error("Wrong JPEG data.")}return n}var m={Byte:1,Ascii:2,Short:3,Long:4,Rational:5,Undefined:7,SLong:9,SRational:10},g={Image:{11:{name:"ProcessingSoftware",type:"Ascii"},254:{name:"NewSubfileType",type:"Long"},255:{name:"SubfileType",type:"Short"},256:{name:"ImageWidth",type:"Long"},257:{name:"ImageLength",type:"Long"},258:{name:"BitsPerSample",type:"Short"},259:{name:"Compression",type:"Short"},262:{name:"PhotometricInterpretation",type:"Short"},263:{name:"Threshholding",type:"Short"},264:{name:"CellWidth",type:"Short"},265:{name:"CellLength",type:"Short"},266:{name:"FillOrder",type:"Short"},269:{name:"DocumentName",type:"Ascii"},270:{name:"ImageDescription",type:"Ascii"},271:{name:"Make",type:"Ascii"},272:{name:"Model",type:"Ascii"},273:{name:"StripOffsets",type:"Long"},274:{name:"Orientation",type:"Short"},277:{name:"SamplesPerPixel",type:"Short"},278:{name:"RowsPerStrip",type:"Long"},279:{name:"StripByteCounts",type:"Long"},282:{name:"XResolution",type:"Rational"},283:{name:"YResolution",type:"Rational"},284:{name:"PlanarConfiguration",type:"Short"},290:{name:"GrayResponseUnit",type:"Short"},291:{name:"GrayResponseCurve",type:"Short"},292:{name:"T4Options",type:"Long"},293:{name:"T6Options",type:"Long"},296:{name:"ResolutionUnit",type:"Short"},301:{name:"TransferFunction",type:"Short"},305:{name:"Software",type:"Ascii"},306:{name:"DateTime",type:"Ascii"},315:{name:"Artist",type:"Ascii"},316:{name:"HostComputer",type:"Ascii"},317:{name:"Predictor",type:"Short"},318:{name:"WhitePoint",type:"Rational"},319:{name:"PrimaryChromaticities",type:"Rational"},320:{name:"ColorMap",type:"Short"},321:{name:"HalftoneHints",type:"Short"},322:{name:"TileWidth",type:"Short"},323:{name:"TileLength",type:"Short"},324:{name:"TileOffsets",type:"Short"},325:{name:"TileByteCounts",type:"Short"},330:{name:"SubIFDs",type:"Long"},332:{name:"InkSet",type:"Short"},333:{name:"InkNames",type:"Ascii"},334:{name:"NumberOfInks",type:"Short"},336:{name:"DotRange",type:"Byte"},337:{name:"TargetPrinter",type:"Ascii"},338:{name:"ExtraSamples",type:"Short"},339:{name:"SampleFormat",type:"Short"},340:{name:"SMinSampleValue",type:"Short"},341:{name:"SMaxSampleValue",type:"Short"},342:{name:"TransferRange",type:"Short"},343:{name:"ClipPath",type:"Byte"},344:{name:"XClipPathUnits",type:"Long"},345:{name:"YClipPathUnits",type:"Long"},346:{name:"Indexed",type:"Short"},347:{name:"JPEGTables",type:"Undefined"},351:{name:"OPIProxy",type:"Short"},512:{name:"JPEGProc",type:"Long"},513:{name:"JPEGInterchangeFormat",type:"Long"},514:{name:"JPEGInterchangeFormatLength",type:"Long"},515:{name:"JPEGRestartInterval",type:"Short"},517:{name:"JPEGLosslessPredictors",type:"Short"},518:{name:"JPEGPointTransforms",type:"Short"},519:{name:"JPEGQTables",type:"Long"},520:{name:"JPEGDCTables",type:"Long"},521:{name:"JPEGACTables",type:"Long"},529:{name:"YCbCrCoefficients",type:"Rational"},530:{name:"YCbCrSubSampling",type:"Short"},531:{name:"YCbCrPositioning",type:"Short"},532:{name:"ReferenceBlackWhite",type:"Rational"},700:{name:"XMLPacket",type:"Byte"},18246:{name:"Rating",type:"Short"},18249:{name:"RatingPercent",type:"Short"},32781:{name:"ImageID",type:"Ascii"},33421:{name:"CFARepeatPatternDim",type:"Short"},33422:{name:"CFAPattern",type:"Byte"},33423:{name:"BatteryLevel",type:"Rational"},33432:{name:"Copyright",type:"Ascii"},33434:{name:"ExposureTime",type:"Rational"},34377:{name:"ImageResources",type:"Byte"},34665:{name:"ExifTag",type:"Long"},34675:{name:"InterColorProfile",type:"Undefined"},34853:{name:"GPSTag",type:"Long"},34857:{name:"Interlace",type:"Short"},34858:{name:"TimeZoneOffset",type:"Long"},34859:{name:"SelfTimerMode",type:"Short"},37387:{name:"FlashEnergy",type:"Rational"},37388:{name:"SpatialFrequencyResponse",type:"Undefined"},37389:{name:"Noise",type:"Undefined"},37390:{name:"FocalPlaneXResolution",type:"Rational"},37391:{name:"FocalPlaneYResolution",type:"Rational"},37392:{name:"FocalPlaneResolutionUnit",type:"Short"},37393:{name:"ImageNumber",type:"Long"},37394:{name:"SecurityClassification",type:"Ascii"},37395:{name:"ImageHistory",type:"Ascii"},37397:{name:"ExposureIndex",type:"Rational"},37398:{name:"TIFFEPStandardID",type:"Byte"},37399:{name:"SensingMethod",type:"Short"},40091:{name:"XPTitle",type:"Byte"},40092:{name:"XPComment",type:"Byte"},40093:{name:"XPAuthor",type:"Byte"},40094:{name:"XPKeywords",type:"Byte"},40095:{name:"XPSubject",type:"Byte"},50341:{name:"PrintImageMatching",type:"Undefined"},50706:{name:"DNGVersion",type:"Byte"},50707:{name:"DNGBackwardVersion",type:"Byte"},50708:{name:"UniqueCameraModel",type:"Ascii"},50709:{name:"LocalizedCameraModel",type:"Byte"},50710:{name:"CFAPlaneColor",type:"Byte"},50711:{name:"CFALayout",type:"Short"},50712:{name:"LinearizationTable",type:"Short"},50713:{name:"BlackLevelRepeatDim",type:"Short"},50714:{name:"BlackLevel",type:"Rational"},50715:{name:"BlackLevelDeltaH",type:"SRational"},50716:{name:"BlackLevelDeltaV",type:"SRational"},50717:{name:"WhiteLevel",type:"Short"},50718:{name:"DefaultScale",type:"Rational"},50719:{name:"DefaultCropOrigin",type:"Short"},50720:{name:"DefaultCropSize",type:"Short"},50721:{name:"ColorMatrix1",type:"SRational"},50722:{name:"ColorMatrix2",type:"SRational"},50723:{name:"CameraCalibration1",type:"SRational"},50724:{name:"CameraCalibration2",type:"SRational"},50725:{name:"ReductionMatrix1",type:"SRational"},50726:{name:"ReductionMatrix2",type:"SRational"},50727:{name:"AnalogBalance",type:"Rational"},50728:{name:"AsShotNeutral",type:"Short"},50729:{name:"AsShotWhiteXY",type:"Rational"},50730:{name:"BaselineExposure",type:"SRational"},50731:{name:"BaselineNoise",type:"Rational"},50732:{name:"BaselineSharpness",type:"Rational"},50733:{name:"BayerGreenSplit",type:"Long"},50734:{name:"LinearResponseLimit",type:"Rational"},50735:{name:"CameraSerialNumber",type:"Ascii"},50736:{name:"LensInfo",type:"Rational"},50737:{name:"ChromaBlurRadius",type:"Rational"},50738:{name:"AntiAliasStrength",type:"Rational"},50739:{name:"ShadowScale",type:"SRational"},50740:{name:"DNGPrivateData",type:"Byte"},50741:{name:"MakerNoteSafety",type:"Short"},50778:{name:"CalibrationIlluminant1",type:"Short"},50779:{name:"CalibrationIlluminant2",type:"Short"},50780:{name:"BestQualityScale",type:"Rational"},50781:{name:"RawDataUniqueID",type:"Byte"},50827:{name:"OriginalRawFileName",type:"Byte"},50828:{name:"OriginalRawFileData",type:"Undefined"},50829:{name:"ActiveArea",type:"Short"},50830:{name:"MaskedAreas",type:"Short"},50831:{name:"AsShotICCProfile",type:"Undefined"},50832:{name:"AsShotPreProfileMatrix",type:"SRational"},50833:{name:"CurrentICCProfile",type:"Undefined"},50834:{name:"CurrentPreProfileMatrix",type:"SRational"},50879:{name:"ColorimetricReference",type:"Short"},50931:{name:"CameraCalibrationSignature",type:"Byte"},50932:{name:"ProfileCalibrationSignature",type:"Byte"},50934:{name:"AsShotProfileName",type:"Byte"},50935:{name:"NoiseReductionApplied",type:"Rational"},50936:{name:"ProfileName",type:"Byte"},50937:{name:"ProfileHueSatMapDims",type:"Long"},50938:{name:"ProfileHueSatMapData1",type:"Float"},50939:{name:"ProfileHueSatMapData2",type:"Float"},50940:{name:"ProfileToneCurve",type:"Float"},50941:{name:"ProfileEmbedPolicy",type:"Long"},50942:{name:"ProfileCopyright",type:"Byte"},50964:{name:"ForwardMatrix1",type:"SRational"},50965:{name:"ForwardMatrix2",type:"SRational"},50966:{name:"PreviewApplicationName",type:"Byte"},50967:{name:"PreviewApplicationVersion",type:"Byte"},50968:{name:"PreviewSettingsName",type:"Byte"},50969:{name:"PreviewSettingsDigest",type:"Byte"},50970:{name:"PreviewColorSpace",type:"Long"},50971:{name:"PreviewDateTime",type:"Ascii"},50972:{name:"RawImageDigest",type:"Undefined"},50973:{name:"OriginalRawFileDigest",type:"Undefined"},50974:{name:"SubTileBlockSize",type:"Long"},50975:{name:"RowInterleaveFactor",type:"Long"},50981:{name:"ProfileLookTableDims",type:"Long"},50982:{name:"ProfileLookTableData",type:"Float"},51008:{name:"OpcodeList1",type:"Undefined"},51009:{name:"OpcodeList2",type:"Undefined"},51022:{name:"OpcodeList3",type:"Undefined"}},Exif:{33434:{name:"ExposureTime",type:"Rational"},33437:{name:"FNumber",type:"Rational"},34850:{name:"ExposureProgram",type:"Short"},34852:{name:"SpectralSensitivity",type:"Ascii"},34855:{name:"ISOSpeedRatings",type:"Short"},34856:{name:"OECF",type:"Undefined"},34864:{name:"SensitivityType",type:"Short"},34865:{name:"StandardOutputSensitivity",type:"Long"},34866:{name:"RecommendedExposureIndex",type:"Long"},34867:{name:"ISOSpeed",type:"Long"},34868:{name:"ISOSpeedLatitudeyyy",type:"Long"},34869:{name:"ISOSpeedLatitudezzz",type:"Long"},36864:{name:"ExifVersion",type:"Undefined"},36867:{name:"DateTimeOriginal",type:"Ascii"},36868:{name:"DateTimeDigitized",type:"Ascii"},37121:{name:"ComponentsConfiguration",type:"Undefined"},37122:{name:"CompressedBitsPerPixel",type:"Rational"},37377:{name:"ShutterSpeedValue",type:"SRational"},37378:{name:"ApertureValue",type:"Rational"},37379:{name:"BrightnessValue",type:"SRational"},37380:{name:"ExposureBiasValue",type:"SRational"},37381:{name:"MaxApertureValue",type:"Rational"},37382:{name:"SubjectDistance",type:"Rational"},37383:{name:"MeteringMode",type:"Short"},37384:{name:"LightSource",type:"Short"},37385:{name:"Flash",type:"Short"},37386:{name:"FocalLength",type:"Rational"},37396:{name:"SubjectArea",type:"Short"},37500:{name:"MakerNote",type:"Undefined"},37510:{name:"UserComment",type:"Ascii"},37520:{name:"SubSecTime",type:"Ascii"},37521:{name:"SubSecTimeOriginal",type:"Ascii"},37522:{name:"SubSecTimeDigitized",type:"Ascii"},40960:{name:"FlashpixVersion",type:"Undefined"},40961:{name:"ColorSpace",type:"Short"},40962:{name:"PixelXDimension",type:"Long"},40963:{name:"PixelYDimension",type:"Long"},40964:{name:"RelatedSoundFile",type:"Ascii"},40965:{name:"InteroperabilityTag",type:"Long"},41483:{name:"FlashEnergy",type:"Rational"},41484:{name:"SpatialFrequencyResponse",type:"Undefined"},41486:{name:"FocalPlaneXResolution",type:"Rational"},41487:{name:"FocalPlaneYResolution",type:"Rational"},41488:{name:"FocalPlaneResolutionUnit",type:"Short"},41492:{name:"SubjectLocation",type:"Short"},41493:{name:"ExposureIndex",type:"Rational"},41495:{name:"SensingMethod",type:"Short"},41728:{name:"FileSource",type:"Undefined"},41729:{name:"SceneType",type:"Undefined"},41730:{name:"CFAPattern",type:"Undefined"},41985:{name:"CustomRendered",type:"Short"},41986:{name:"ExposureMode",type:"Short"},41987:{name:"WhiteBalance",type:"Short"},41988:{name:"DigitalZoomRatio",type:"Rational"},41989:{name:"FocalLengthIn35mmFilm",type:"Short"},41990:{name:"SceneCaptureType",type:"Short"},41991:{name:"GainControl",type:"Short"},41992:{name:"Contrast",type:"Short"},41993:{name:"Saturation",type:"Short"},41994:{name:"Sharpness",type:"Short"},41995:{name:"DeviceSettingDescription",type:"Undefined"},41996:{name:"SubjectDistanceRange",type:"Short"},42016:{name:"ImageUniqueID",type:"Ascii"},42032:{name:"CameraOwnerName",type:"Ascii"},42033:{name:"BodySerialNumber",type:"Ascii"},42034:{name:"LensSpecification",type:"Rational"},42035:{name:"LensMake",type:"Ascii"},42036:{name:"LensModel",type:"Ascii"},42037:{name:"LensSerialNumber",type:"Ascii"},42240:{name:"Gamma",type:"Rational"}},GPS:{0:{name:"GPSVersionID",type:"Byte"},1:{name:"GPSLatitudeRef",type:"Ascii"},2:{name:"GPSLatitude",type:"Rational"},3:{name:"GPSLongitudeRef",type:"Ascii"},4:{name:"GPSLongitude",type:"Rational"},5:{name:"GPSAltitudeRef",type:"Byte"},6:{name:"GPSAltitude",type:"Rational"},7:{name:"GPSTimeStamp",type:"Rational"},8:{name:"GPSSatellites",type:"Ascii"},9:{name:"GPSStatus",type:"Ascii"},10:{name:"GPSMeasureMode",type:"Ascii"},11:{name:"GPSDOP",type:"Rational"},12:{name:"GPSSpeedRef",type:"Ascii"},13:{name:"GPSSpeed",type:"Rational"},14:{name:"GPSTrackRef",type:"Ascii"},15:{name:"GPSTrack",type:"Rational"},16:{name:"GPSImgDirectionRef",type:"Ascii"},17:{name:"GPSImgDirection",type:"Rational"},18:{name:"GPSMapDatum",type:"Ascii"},19:{name:"GPSDestLatitudeRef",type:"Ascii"},20:{name:"GPSDestLatitude",type:"Rational"},21:{name:"GPSDestLongitudeRef",type:"Ascii"},22:{name:"GPSDestLongitude",type:"Rational"},23:{name:"GPSDestBearingRef",type:"Ascii"},24:{name:"GPSDestBearing",type:"Rational"},25:{name:"GPSDestDistanceRef",type:"Ascii"},26:{name:"GPSDestDistance",type:"Rational"},27:{name:"GPSProcessingMethod",type:"Undefined"},28:{name:"GPSAreaInformation",type:"Undefined"},29:{name:"GPSDateStamp",type:"Ascii"},30:{name:"GPSDifferential",type:"Short"},31:{name:"GPSHPositioningError",type:"Rational"}},Interop:{1:{name:"InteroperabilityIndex",type:"Ascii"}}};g["0th"]=g.Image,g["1st"]=g.Image,n.TAGS=g,n.ImageIFD={ProcessingSoftware:11,NewSubfileType:254,SubfileType:255,ImageWidth:256,ImageLength:257,BitsPerSample:258,Compression:259,PhotometricInterpretation:262,Threshholding:263,CellWidth:264,CellLength:265,FillOrder:266,DocumentName:269,ImageDescription:270,Make:271,Model:272,StripOffsets:273,Orientation:274,SamplesPerPixel:277,RowsPerStrip:278,StripByteCounts:279,XResolution:282,YResolution:283,PlanarConfiguration:284,GrayResponseUnit:290,GrayResponseCurve:291,T4Options:292,T6Options:293,ResolutionUnit:296,TransferFunction:301,Software:305,DateTime:306,Artist:315,HostComputer:316,Predictor:317,WhitePoint:318,PrimaryChromaticities:319,ColorMap:320,HalftoneHints:321,TileWidth:322,TileLength:323,TileOffsets:324,TileByteCounts:325,SubIFDs:330,InkSet:332,InkNames:333,NumberOfInks:334,DotRange:336,TargetPrinter:337,ExtraSamples:338,SampleFormat:339,SMinSampleValue:340,SMaxSampleValue:341,TransferRange:342,ClipPath:343,XClipPathUnits:344,YClipPathUnits:345,Indexed:346,JPEGTables:347,OPIProxy:351,JPEGProc:512,JPEGInterchangeFormat:513,JPEGInterchangeFormatLength:514,JPEGRestartInterval:515,JPEGLosslessPredictors:517,JPEGPointTransforms:518,JPEGQTables:519,JPEGDCTables:520,JPEGACTables:521,YCbCrCoefficients:529,YCbCrSubSampling:530,YCbCrPositioning:531,ReferenceBlackWhite:532,XMLPacket:700,Rating:18246,RatingPercent:18249,ImageID:32781,CFARepeatPatternDim:33421,CFAPattern:33422,BatteryLevel:33423,Copyright:33432,ExposureTime:33434,ImageResources:34377,ExifTag:34665,InterColorProfile:34675,GPSTag:34853,Interlace:34857,TimeZoneOffset:34858,SelfTimerMode:34859,FlashEnergy:37387,SpatialFrequencyResponse:37388,Noise:37389,FocalPlaneXResolution:37390,FocalPlaneYResolution:37391,FocalPlaneResolutionUnit:37392,ImageNumber:37393,SecurityClassification:37394,ImageHistory:37395,ExposureIndex:37397,TIFFEPStandardID:37398,SensingMethod:37399,XPTitle:40091,XPComment:40092,XPAuthor:40093,XPKeywords:40094,XPSubject:40095,PrintImageMatching:50341,DNGVersion:50706,DNGBackwardVersion:50707,UniqueCameraModel:50708,LocalizedCameraModel:50709,CFAPlaneColor:50710,CFALayout:50711,LinearizationTable:50712,BlackLevelRepeatDim:50713,BlackLevel:50714,BlackLevelDeltaH:50715,BlackLevelDeltaV:50716,WhiteLevel:50717,DefaultScale:50718,DefaultCropOrigin:50719,DefaultCropSize:50720,ColorMatrix1:50721,ColorMatrix2:50722,CameraCalibration1:50723,CameraCalibration2:50724,ReductionMatrix1:50725,ReductionMatrix2:50726,AnalogBalance:50727,AsShotNeutral:50728,AsShotWhiteXY:50729,BaselineExposure:50730,BaselineNoise:50731,BaselineSharpness:50732,BayerGreenSplit:50733,LinearResponseLimit:50734,CameraSerialNumber:50735,LensInfo:50736,ChromaBlurRadius:50737,AntiAliasStrength:50738,ShadowScale:50739,DNGPrivateData:50740,MakerNoteSafety:50741,CalibrationIlluminant1:50778,CalibrationIlluminant2:50779,BestQualityScale:50780,RawDataUniqueID:50781,OriginalRawFileName:50827,OriginalRawFileData:50828,ActiveArea:50829,MaskedAreas:50830,AsShotICCProfile:50831,AsShotPreProfileMatrix:50832,CurrentICCProfile:50833,CurrentPreProfileMatrix:50834,ColorimetricReference:50879,CameraCalibrationSignature:50931,ProfileCalibrationSignature:50932,AsShotProfileName:50934,NoiseReductionApplied:50935,ProfileName:50936,ProfileHueSatMapDims:50937,ProfileHueSatMapData1:50938,ProfileHueSatMapData2:50939,ProfileToneCurve:50940,ProfileEmbedPolicy:50941,ProfileCopyright:50942,ForwardMatrix1:50964,ForwardMatrix2:50965,PreviewApplicationName:50966,PreviewApplicationVersion:50967,PreviewSettingsName:50968,PreviewSettingsDigest:50969,PreviewColorSpace:50970,PreviewDateTime:50971,RawImageDigest:50972,OriginalRawFileDigest:50973,SubTileBlockSize:50974,RowInterleaveFactor:50975,ProfileLookTableDims:50981,ProfileLookTableData:50982,OpcodeList1:51008,OpcodeList2:51009,OpcodeList3:51022,NoiseProfile:51041},n.ExifIFD={ExposureTime:33434,FNumber:33437,ExposureProgram:34850,SpectralSensitivity:34852,ISOSpeedRatings:34855,OECF:34856,SensitivityType:34864,StandardOutputSensitivity:34865,RecommendedExposureIndex:34866,ISOSpeed:34867,ISOSpeedLatitudeyyy:34868,ISOSpeedLatitudezzz:34869,ExifVersion:36864,DateTimeOriginal:36867,DateTimeDigitized:36868,ComponentsConfiguration:37121,CompressedBitsPerPixel:37122,ShutterSpeedValue:37377,ApertureValue:37378,BrightnessValue:37379,ExposureBiasValue:37380,MaxApertureValue:37381,SubjectDistance:37382,MeteringMode:37383,LightSource:37384,Flash:37385,FocalLength:37386,SubjectArea:37396,MakerNote:37500,UserComment:37510,SubSecTime:37520,SubSecTimeOriginal:37521,SubSecTimeDigitized:37522,FlashpixVersion:40960,ColorSpace:40961,PixelXDimension:40962,PixelYDimension:40963,RelatedSoundFile:40964,InteroperabilityTag:40965,FlashEnergy:41483,SpatialFrequencyResponse:41484,FocalPlaneXResolution:41486,FocalPlaneYResolution:41487,FocalPlaneResolutionUnit:41488,SubjectLocation:41492,ExposureIndex:41493,SensingMethod:41495,FileSource:41728,SceneType:41729,CFAPattern:41730,CustomRendered:41985,ExposureMode:41986,WhiteBalance:41987,DigitalZoomRatio:41988,FocalLengthIn35mmFilm:41989,SceneCaptureType:41990,GainControl:41991,Contrast:41992,Saturation:41993,Sharpness:41994,DeviceSettingDescription:41995,SubjectDistanceRange:41996,ImageUniqueID:42016,CameraOwnerName:42032,BodySerialNumber:42033,LensSpecification:42034,LensMake:42035,LensModel:42036,LensSerialNumber:42037,Gamma:42240},n.GPSIFD={GPSVersionID:0,GPSLatitudeRef:1,GPSLatitude:2,GPSLongitudeRef:3,GPSLongitude:4,GPSAltitudeRef:5,GPSAltitude:6,GPSTimeStamp:7,GPSSatellites:8,GPSStatus:9,GPSMeasureMode:10,GPSDOP:11,GPSSpeedRef:12,GPSSpeed:13,GPSTrackRef:14,GPSTrack:15,GPSImgDirectionRef:16,GPSImgDirection:17,GPSMapDatum:18,GPSDestLatitudeRef:19,GPSDestLatitude:20,GPSDestLongitudeRef:21,GPSDestLongitude:22,GPSDestBearingRef:23,GPSDestBearing:24,GPSDestDistanceRef:25,GPSDestDistance:26,GPSProcessingMethod:27,GPSAreaInformation:28,GPSDateStamp:29,GPSDifferential:30,GPSHPositioningError:31},n.InteropIFD={InteroperabilityIndex:1},n.GPSHelper={degToDmsRational:function(e){var t=Math.abs(e),n=t%1*60,r=n%1*60;return[[Math.floor(t),1],[Math.floor(n),1],[Math.round(100*r),100]]},dmsRationalToDeg:function(e,t){var n="S"===t||"W"===t?-1:1;return(e[0][0]/e[0][1]+e[1][0]/e[1][1]/60+e[2][0]/e[2][1]/3600)*n}},e.exports&&(t=e.exports=n),t.piexif=n}()}));const Iq=async(e,t,n)=>{const r=await(e=>new Promise((t,n)=>{const r=new FileReader;r.onloadend=()=>t(r.result),r.readAsDataURL(e)}))(e),a=Sq.load(r),s=(await navigator.mediaDevices.enumerateDevices()).filter(e=>"videoinput"===e.kind).map(e=>e.label),i={width:n.width,height:n.height,usedCamera:t.label,camerasOnDevice:s},o={"0th":Object.assign(Object.assign({},a["0th"]),{[Sq.ImageIFD.Model]:i.usedCamera,[Sq.ImageIFD.ImageWidth]:i.width,[Sq.ImageIFD.ImageLength]:i.height}),Exif:Object.assign(Object.assign({},a.Exif),{[Sq.ExifIFD.UserComment]:JSON.stringify(i)}),GPS:Object.assign({},a.GPS),Interop:Object.assign({},a.Interop),"1st":Object.assign({},a["1st"]),thumbnail:a.thumbnail},u=Sq.dump(o),l=Sq.insert(u,r);return await fetch(l).then(e=>e.blob())},Aq=new Image;var Eq;Aq.src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjIyNC45OTk5OTk5OTk5OTk5NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHZlcnNpb249IjEuMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPGcgc3Ryb2tlPSJudWxsIiBpZD0iTGF5ZXIgMSI+CiAgIDxwYXRoIHN0cm9rZT0iIzRjYTU4NSIgaWQ9InN2Z18xIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBmaWxsPSJub25lIiBkPSJtNzQuMjc3NjUsNi45Mjc2MWMtMTEuMzc1OTcsLTAuMDE3MTMgLTMzLjU2NTUxLDUuMTA0MzMgLTQ2LjgxMzE2LDE5LjQ5NDgxYy02Ljc0MTQzLDcuMzIyOTIgLTE4LjEyMjY5LDIzLjA2OTY3IC0xOS4yNjc1OCw1OS42MTM2OWMtMC41MTkwNiwxNi41NjkyMSA1LjA0NTI0LDYwLjYyNTMzIDEwLjI0MDA2LDc2LjQ2Nzc1YzMuNjMxMywxMS4wNzQ2OCAyNy40ODIxNSw0My45MzM0OSA0NC40OTA2LDUzLjY4MjUxYzQuODA3OTEsMi43NTU0NiAxMS4yOTY2OCwyLjY4MjUxIDEyLjQyMjU1LDIuNjgyNTFjMS4xODg3NiwtMC4wODQ1NyA3LjMzMDI2LDAuMDcyOTQgMTIuMTM3NjUsLTIuNjgyNTFjMTcuMDA4NDYsLTkuNzQ5MDIgNDAuNDAyMDgsLTQyLjc2ODUxIDQ0LjQ5MDYsLTUzLjY4MjUxYzQuNDAwMzgsLTExLjc0NDkxIDEwLjc1OTY1LC01OS44OTg1NCAxMC4yNDAwNiwtNzYuNDY3NzVjLTEuMTQ0ODksLTM2LjU0NDAyIC0xMi41MjYxNSwtNTIuMjkwNzcgLTE5LjI2NzU4LC01OS42MTM2OWMtMTMuMjQ3NjUsLTE0LjM5MDQ4IC0zNS4zMDY2MywtMTkuNTI5MzMgLTQ2Ljc3ODI3LC0xOS40OTQ4MWMtMC43NDY4OCwwLjAwMjIyIC0xLjg5NDk0LDAgLTEuODk0OTQsMHoiIHN0cm9rZS13aWR0aD0iNy42NSIvPgogIDwvZz4KIDwvZz4KPC9zdmc+Cg==",function(e){e.JPEG="image/jpeg",e.PNG="image/png"}(Eq||(Eq={}));class Nq{constructor(e,t){this.showMask=!1,this.videoSize={width:0,height:0},this.streamPaused=!1,this.pauseStream=()=>{this.streamPaused=!0,this.videoElement.pause(),this.dropMask(),this.faceDetection&&kq.getInstance().stopDetector()},this.device=e,this.detector=kq.getInstance(this,e.isMobile,t)}setShowMask(e){this.showMask=e}setFaceDetection(e){this.faceDetection=e}setProbabilityThreshold(e){kq.getInstance().setProbabilityThreshold(e)}setCallbackErrors(e){this.callbackErrors=e}setCallbackAutoCapturing(e){this.callbackAutoCapturing=e}setCallbackFaceDetectionErrors(e){this.callbackFaceDetectionErrors=e}static getInstance(e,t){return Nq.instance||(Nq.instance=new Nq(e,t)),Nq.instance}returnErrors(e){this.callbackFaceDetectionErrors(e)}autoCapturing(){this.callbackAutoCapturing()}updateHtmlElements(e,t){this.videoElement=e,this.canvasElement=t,this.detector.updateHtmlElements(e)}async startDetection(){return this.detector.startDetector()}static orientationChange(){Nq.instance&&Nq.getInstance().drawMask()}startStream(e){this.stream&&this.stream.getTracks().forEach(e=>e.stop()),this.stream=e,"srcObject"in this.videoElement?this.videoElement.srcObject=e:this.videoElement.src=window.URL.createObjectURL(e),this.videoElement.play().then(()=>{this.streamPaused=!1,l.cameraReadyEvent(),this.drawMask(),this.faceDetection&&this.startDetection()})}async initStream(e){this.startStream(e)}async resumeStream(){this.streamPaused=!1,await this.videoElement.play(),this.drawMask(),this.faceDetection&&await kq.getInstance().startDetector()}updateCanvasSize(e){this.videoSize={width:this.videoElement.videoWidth,height:this.videoElement.videoHeight},e.width=this.videoSize.width,e.height=this.videoSize.height}dropStream(){this.streamStopped()||(this.stream.getTracks().forEach(e=>e.stop()),this.videoElement.srcObject=null),this.faceDetection&&kq.getInstance().stopDetector()}streamStopped(){return!(this.stream&&this.stream.getTracks&&this.stream.getTracks().length>0)}drawMask(){this.showMask&&!this.streamPaused&&setTimeout(()=>{this.updateCanvasSize(this.canvasElement);const e=this.canvasElement,t=e.getContext("2d"),n=e.width/Aq.width,r=e.height/Aq.height,a=Math.min(n,r),s=e.width{const t=document.createElement("canvas");t.width=this.videoElement.videoWidth,t.height=this.videoElement.videoHeight,e([await this.getFrame(t)])})}getFrame(e){return new Promise(t=>{e.getContext("2d").drawImage(this.videoElement,0,0,e.width,e.height),e.toBlob(e=>{if(e.type!==Eq.JPEG||this.device.isIos)t(e);else try{Iq(e,this.stream.getTracks()[0],this.videoSize).then(e=>t(e))}catch(n){t(e),this.callbackErrors(n,!1)}},Eq.PNG,1)})}}window.addEventListener("resize",Nq.orientationChange,!1),window.addEventListener("orientationchange",Nq.orientationChange,!1);let Cq=class{constructor(e){Object(u.f)(this,e),this.eventVideoStarted=Object(u.b)(this,"videoStarted",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.errorCameraEvent=Object(u.b)(this,"errorCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.callbackErrors=(e,t)=>{t?(this.errorCameraEvent.emit(e),this.eventCloseCamera.emit()):this.errorCameraEvent.emit(e)},this.callbackAutoCapturing=()=>{this.device.isMobile?this.eventMakePhoto.emit():this.eventTakePhoto.emit()},this.callbackFaceDetectionErrors=e=>{l.detectionError(e)}}componentDidLoad(){this.startStream()}render(){const e="camera "+(this.device.isMobile?"cameraMobile":"");return Object(u.d)("div",{class:e},Object(u.d)("video",{loop:!0,autoplay:!0,playsinline:!0,muted:!0,class:"cameraVideo",ref:e=>this.cameraVideo=e}),Object(u.d)("canvas",{class:"cameraCanvas",ref:e=>this.cameraCanvas=e}))}startStream(){Nq.instance||Nq.getInstance(this.device,this.modelPath);const e=Nq.getInstance();e.updateHtmlElements(this.cameraVideo,this.cameraCanvas),e.setShowMask(this.showMask),e.setFaceDetection(this.faceDetection),e.setProbabilityThreshold(this.probabilityThreshold),e.setCallbackErrors(this.callbackErrors),e.setCallbackAutoCapturing(this.callbackAutoCapturing),e.setCallbackFaceDetectionErrors(this.callbackFaceDetectionErrors)}};Cq.style=".camera{width:100%;height:100%;color:white;display:flex;align-items:center;justify-content:center;position:relative}.cameraCanvas{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);max-width:100%;max-height:100%;z-index:2}.cameraVideo{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);z-index:1;position:absolute;max-width:100%;max-height:100%}.cameraMobile{position:fixed;top:0;left:0;background:black}.canvas-on-video{max-width:100%;max-height:100%;position:absolute;left:50%;top:50%;z-index:2;transform:scale(-1, 1)}";let Tq=class{constructor(e){Object(u.f)(this,e),this.updateState=()=>{this._showMask="true"===this.show_mask,this._disable_control_panel="true"===this.disable_control_panel,this._face_detection="true"===this.face_detection,this._stopAfterCapturing="true"===this.stop_after_capturing,this._probabilityThreshold=this.probability_threshold?+this.probability_threshold:50,this.url_logo=this.url_logo?this.url_logo:"data:image/png;charset=utf-8;base64,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",this._debug="true"===this.debug,kq.debug=this._debug},this.photoIsReady=e=>{this._stopAfterCapturing&&this.closeCamera(),l.captureEvent(e)},this.enableButton=()=>{this._resolutionOnPhoto=!0},this.updateState(),this._cameraStatus=0,this._resolutionOnPhoto=!1,this._device=xq(),this._mobile=this._device.isMobile,this._mobileMakePhoto=!1}videoStarted(){this._resolutionOnPhoto=!0}async retakePhoto(){this._mobileMakePhoto=!1,await Nq.getInstance().resumeStream()}takePhoto(){Nq.getInstance().takePhoto().then(e=>{this.photoIsReady(e)})}async openCamera(){this._cameraStatus=1;const e=this._device.isMac?{audio:!1,video:{facingMode:"user",width:1920,height:1080}}:{audio:!1,video:{facingMode:"user",width:{ideal:1920},height:{ideal:1080}}};setTimeout(()=>{navigator.mediaDevices.getUserMedia(e).then(e=>{Nq.getInstance().initStream(e),this.videoStarted()}).catch(e=>{this.closeCamera(),l.errorEvent(e)})},100)}async loadModels(e){await kq.initDetector(e.detail.path)}errorCamera(e){l.errorEvent(e.detail.message)}closeCamera(){Nq.instance&&(this._cameraStatus=0,l.closeEvent(),Nq.getInstance().dropStream(),this._mobileMakePhoto=!1,this._resolutionOnPhoto=!1)}makePhoto(){this._mobile?(this._mobileMakePhoto=!0,Nq.getInstance().pauseStream()):this.takePhoto()}componentWillLoad(){l.init(this.component),navigator.mediaDevices||l.errorEvent("This browser does not support webRTC")}componentDidUpdate(){this.updateState()}render(){let e;return e=this._cameraStatus?Object(u.d)("camera-comp",{class:"block",showMask:this._showMask,device:this._device,faceDetection:this._face_detection,modelPath:this.model_path,probabilityThreshold:this._probabilityThreshold}):Object(u.d)("img",{src:this.url_logo,class:"logo",style:this.logo_style?JSON.parse(this.logo_style):"",alt:"logo"}),Object(u.d)("div",{class:"cameraContainer",id:"cameraContainer",style:{backgroundColor:this.background_color}},Object(u.d)("div",{class:"wrapperCamera",style:{height:this._disable_control_panel?"100%":"65%"}},e),Object(u.d)("control-panel",{class:"block",mobile:this._mobile,disableControlPanel:this._disable_control_panel,cameraStatus:this._cameraStatus,resolutionOnPhoto:this._resolutionOnPhoto,mobileMakePhoto:this._mobileMakePhoto,faceDetection:this._face_detection}))}get component(){return Object(u.c)(this)}};Tq.style=".cameraContainer{width:100%;height:100%;z-index:10;position:relative;overflow:hidden}.logo{max-height:450px;max-width:450px}.wrapperCamera{display:flex;justify-content:center;align-items:center}.block{width:100%;height:100%}@media screen and (orientation: portrait){.history{width:100vw;font-size:20px}@media screen and (max-height: 667px){.logo{background-size:120px;max-height:120px;max-width:120px}}@media screen and (min-height: 668px) and (max-height: 812px){.logo{background-size:140px;max-height:140px;max-width:140px}}@media (max-height: 667px){.logo{margin:0 auto}}}@media screen and (max-height: 414px){.logo{background-size:140px;max-height:140px;max-width:140px}}";const Rq=(e,t)=>[...t];let _q=class{constructor(e){Object(u.f)(this,e),this.eventOpenCamera=Object(u.b)(this,"openCamera",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventRetakePhoto=Object(u.b)(this,"retakePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.makePhoto=()=>{this.eventMakePhoto.emit()},this.closeCamera=()=>{this.eventCloseCamera.emit()},this.openCamera=()=>{this.eventOpenCamera.emit()},this.takePhoto=()=>{this.eventTakePhoto.emit()},this.retakePhoto=async()=>{this.eventRetakePhoto.emit()}}render(){return Object(u.d)("div",{class:"controlPanel"+(this.mobile?" controlMobile":"")},this.mobile?Object(u.d)("div",null,this.cameraStatus?Object(u.d)("div",null,this.mobileMakePhoto?Object(u.d)("div",null,Object(u.d)("div",{onClick:this.retakePhoto,class:"retake"},"retake"),Object(u.d)("img",{onClick:this.takePhoto,class:"shoot takePhoto",src:"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMjEuMC4yLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDggNDg7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iOTZweCIgaGVpZ2h0PSI5NnB4Ij4KPHBhdGggc3R5bGU9ImZpbGw6I0M4RTZDOTsiIGQ9Ik00NCwyNGMwLDExLjA0NS04Ljk1NSwyMC0yMCwyMFM0LDM1LjA0NSw0LDI0UzEyLjk1NSw0LDI0LDRTNDQsMTIuOTU1LDQ0LDI0eiIvPgo8cGF0aCBzdHlsZT0iZmlsbDojNENBRjUwOyIgZD0iTTM0LjU4NiwxNC41ODZsLTEzLjU3LDEzLjU4NmwtNS42MDItNS41ODZsLTIuODI4LDIuODI4bDguNDM0LDguNDE0bDE2LjM5NS0xNi40MTRMMzQuNTg2LDE0LjU4NnoiLz4KPC9zdmc+Cg=="})):Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto,class:"shoot"}),Object(u.d)("div",{onClick:this.closeCamera,class:"close"},"close")):Object(u.d)("div",null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)("button",{onClick:this.openCamera},"Turn on camera"))):Object(u.d)(Rq,null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)(Rq,null,this.cameraStatus?Object(u.d)(Rq,null,Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto},"Capture"),Object(u.d)("button",{onClick:this.closeCamera,class:"cameraOff"},"Close camera")):Object(u.d)("button",{onClick:this.openCamera},"Open camera"))))}};_q.style='.controlPanel{height:35%;display:flex;justify-content:space-evenly;align-items:center;width:100%;max-width:450px;margin:auto}.buttons{width:100%;max-width:450px;display:flex;justify-content:space-evenly;align-items:center}button{width:164px;height:50px;border:none;margin-bottom:10px;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;color:#fff;font-family:"Avenir", Helvetica, sans-serif;font-weight:600;font-size:16px;background-color:#4ca585;outline:none;cursor:pointer}button[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.cameraOff{background-color:#667a87}.cameraOff:hover{background-color:#92a8b5}.shoot{width:50px;height:50px;border-radius:25px;border:2px solid white;outline:none;background-color:red;position:fixed;left:calc(50% - 25px);bottom:10px}.shoot[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.close{position:fixed;right:6vw;top:2vh;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.retake{position:fixed;right:6vw;bottom:35px;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.takePhoto{width:46px;height:46px;bottom:20px;background:none}@media screen and (orientation:landscape) and (min-width: 360px){.shoot{bottom:calc(50% - 25px);left:auto;right:5vw}}'}.call(this,"/index.js",n(124),"/",n(33),n(238).Buffer,n(242).setImmediate)},function(e,t,n){"use strict";(function(e){ +/** @license See the LICENSE file. */(e,{width:this.videoElement.videoWidth,height:this.videoElement.videoHeight}),n=new hq,r=this.checkNumberFaces(t);return n.FACE_NOT_FOUND=!r&&0===t.length,n.TOO_MANY_FACES=!r&&t.length>this.MAX_NUMBER_FACES,r&&(wq&&(n.FACE_ANGLE_TOO_LARGE=!this.checkHeadRotation(t)),n.PROBABILITY_TOO_SMALL=!this.checkProbability(t),n.FACE_TOO_SMALL=!this.checkFaceSize(t),n.FACE_CLOSE_TO_BORDER=!this.checkFaceIndent(t)),n}autoCapturing(){kq.debug&&console.info(this.counterSuccessfulResults),this.counterSuccessfulResults>=this.DEFAULT_NUMBER_SUCCESSFUL_RESULTS_FOR_AUTO_CAPTURING&&(this.stream.autoCapturing(),this.counterSuccessfulResults=0)}checkNumberFaces(e){return e.length===this.MAX_NUMBER_FACES}checkProbability(e){return e[0].detection.score>+this.probabilityThreshold/100}checkFaceSize(e){const t=e[0].detection.box,{width:n,height:r,area:a}=t,{imageHeight:s,imageWidth:i}=e[0].detection,o=100/(s*i/a);return Math.min(n/this.videoRatio,r/this.videoRatio)>(this.isMobile?this.MIN_FACE_SIZE_FOR_MOBILE:this.MIN_FACE_SIZE_FOR_DESKTOP)&&o>(this.isMobile?this.MIN_OCCUPIED_SPACE_FOR_MOBILE:this.MIN_OCCUPIED_SPACE_FOR_DESKTOP)}checkFaceIndent(e){const t=e[0].detection.box,{imageHeight:n,imageWidth:r}=e[0].detection,{top:a,left:s,bottom:i,right:o}=t,u=s,l=r-o,c=n-i;return!(athis.MAX_ANGLE_TURN_HEAD||-1*a[2]>this.MAX_ANGLE_TURN_HEAD?this.headTurnCounter++:(this.counterSuccessfulHeadTurns++,this.counterSuccessfulHeadTurns>=5&&(this.headTurnCounter=0,this.counterSuccessfulHeadTurns=0)),this.headTurnCounter<=1}drawFaces(e){this.innerCanvas||this.createCanvasForDrawingMask(this.videoElement);const t=this.innerCanvas;if(!t)return console.error("no canvas for drawing");const n=t.getContext("2d");if(n){n.clearRect(0,0,t.width,t.height),n.font='small-caps 20px "Segoe UI"',n.fillStyle="white";for(const t of e){n.lineWidth=3,n.strokeStyle="deepskyblue",n.fillStyle="deepskyblue",n.globalAlpha=.6,n.beginPath(),n.rect(t.detection.box.x,t.detection.box.y,t.detection.box.width,t.detection.box.height),n.stroke(),n.globalAlpha=1,n.globalAlpha=.8,n.fillStyle="lightblue";const e=2;for(let r=0;r"+d("B",e.length),e)}function a(e){return h(">"+d("H",e.length),e)}function s(e){return h(">"+d("L",e.length),e)}function i(e,t,n){var i,o,u,l,c="",p="";if("Byte"==t)(i=e.length)<=4?p=r(e)+d("\0",4-i):(p=h(">L",[n]),c=r(e));else if("Short"==t)(i=e.length)<=2?p=a(e)+d("\0\0",2-i):(p=h(">L",[n]),c=a(e));else if("Long"==t)(i=e.length)<=1?p=s(e):(p=h(">L",[n]),c=s(e));else if("Ascii"==t)(i=(o=e+"\0").length)>4?(p=h(">L",[n]),c=o):p=o+d("\0",4-i);else if("Rational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">L",[u])+h(">L",[l]);else{i=e.length,o="";for(var f=0;fL",[u])+h(">L",[l])}p=h(">L",[n]),c=o}else if("SRational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">l",[u])+h(">l",[l]);else{i=e.length,o="";for(f=0;fl",[u])+h(">l",[l])}p=h(">L",[n]),c=o}else"Undefined"==t&&((i=e.length)>4?(p=h(">L",[n]),c=e):p=e+d("\0",4-i));return[h(">L",[i]),p,c]}function o(e,t,n){var r,a=Object.keys(e).length,s=h(">H",[a]);r=["0th","1st"].indexOf(t)>-1?2+12*a+4:2+12*a;var o="",u="";for(var l in e)if("string"==typeof l&&(l=parseInt(l)),!("0th"==t&&[34665,34853].indexOf(l)>-1||"Exif"==t&&40965==l||"1st"==t&&[513,514].indexOf(l)>-1)){var c=e[l],p=h(">H",[l]),d=g[t][l].type,f=h(">H",[m[d]]);"number"==typeof c&&(c=[c]);var y=i(c,d,8+r+n+u.length);o+=p+f+y[0]+y[1],u+=y[2]}return[s+o,u]}function u(e){var t;if("ÿØ"==e.slice(0,2))t=function(e){for(var t,n=0;n-1)this.tiftag=e;else{if("Exif"!=e.slice(0,4))throw new Error("Given file is neither JPEG nor TIFF.");this.tiftag=e.slice(6)}}if(n.version="1.0.4",n.remove=function(e){var t=!1;if("ÿØ"==e.slice(0,2));else{if("data:image/jpeg;base64,"!=e.slice(0,23)&&"data:image/jpg;base64,"!=e.slice(0,22))throw new Error("Given data is not jpeg.");e=c(e.split(",")[1]),t=!0}var n=f(e).filter((function(e){return!("ÿá"==e.slice(0,2)&&"Exif\0\0"==e.slice(4,10))})).join("");return t&&(n="data:image/jpeg;base64,"+l(n)),n},n.insert=function(e,t){var n=!1;if("Exif\0\0"!=e.slice(0,6))throw new Error("Given data is not exif.");if("ÿØ"==t.slice(0,2));else{if("data:image/jpeg;base64,"!=t.slice(0,23)&&"data:image/jpg;base64,"!=t.slice(0,22))throw new Error("Given data is not jpeg.");t=c(t.split(",")[1]),n=!0}var r="ÿá"+h(">H",[e.length+2])+e,a=function(e,t){var n=!1,r=[];e.forEach((function(a,s){"ÿá"==a.slice(0,2)&&"Exif\0\0"==a.slice(4,10)&&(n?r.unshift(s):(e[s]=t,n=!0))})),r.forEach((function(t){e.splice(t,1)})),!n&&t&&(e=[e[0],t].concat(e.slice(1)));return e.join("")}(f(t),r);return n&&(a="data:image/jpeg;base64,"+l(a)),a},n.load=function(e){var t;if("string"!=typeof e)throw new Error("'load' gots invalid type argument.");if("ÿØ"==e.slice(0,2))t=e;else if("data:image/jpeg;base64,"==e.slice(0,23)||"data:image/jpg;base64,"==e.slice(0,22))t=c(e.split(",")[1]);else{if("Exif"!=e.slice(0,4))throw new Error("'load' gots invalid file data.");t=e.slice(6)}var n={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null},r=new u(t);if(null===r.tiftag)return n;"II"==r.tiftag.slice(0,2)?r.endian_mark="<":r.endian_mark=">";var a=p(r.endian_mark+"L",r.tiftag.slice(4,8))[0];n["0th"]=r.get_ifd(a,"0th");var s=n["0th"].first_ifd_pointer;if(delete n["0th"].first_ifd_pointer,34665 in n["0th"]&&(a=n["0th"][34665],n.Exif=r.get_ifd(a,"Exif")),34853 in n["0th"]&&(a=n["0th"][34853],n.GPS=r.get_ifd(a,"GPS")),40965 in n.Exif&&(a=n.Exif[40965],n.Interop=r.get_ifd(a,"Interop")),"\0\0\0\0"!=s&&(a=p(r.endian_mark+"L",s)[0],n["1st"]=r.get_ifd(a,"1st"),513 in n["1st"]&&514 in n["1st"])){var i=n["1st"][513]+n["1st"][514],o=r.tiftag.slice(n["1st"][513],i);n.thumbnail=o}return n},n.dump=function(e){var t,r,a,s,i,u,l=(t=e,JSON.parse(JSON.stringify(t))),c=!1,p=!1,d=!1,g=!1;r="0th"in l?l["0th"]:{},"Exif"in l&&Object.keys(l.Exif).length||"Interop"in l&&Object.keys(l.Interop).length?(r[34665]=1,c=!0,a=l.Exif,"Interop"in l&&Object.keys(l.Interop).length?(a[40965]=1,d=!0,s=l.Interop):Object.keys(a).indexOf(n.ExifIFD.InteroperabilityTag.toString())>-1&&delete a[40965]):Object.keys(r).indexOf(n.ImageIFD.ExifTag.toString())>-1&&delete r[34665],"GPS"in l&&Object.keys(l.GPS).length?(r[n.ImageIFD.GPSTag]=1,p=!0,i=l.GPS):Object.keys(r).indexOf(n.ImageIFD.GPSTag.toString())>-1&&delete r[n.ImageIFD.GPSTag],"1st"in l&&"thumbnail"in l&&null!=l.thumbnail&&(g=!0,l["1st"][513]=1,l["1st"][514]=1,u=l["1st"]);var y,b,v,x=o(r,"0th",0),w=x[0].length+12*c+12*p+4+x[1].length,k="",S=0,I="",A=0,E="",N=0,C="";(c&&(S=(y=o(a,"Exif",w))[0].length+12*d+y[1].length),p&&(A=(I=o(i,"GPS",w+S).join("")).length),d)&&(N=(E=o(s,"Interop",w+S+A).join("")).length);if(g&&(b=o(u,"1st",w+S+A+N),(v=function(e){var t=f(e);for(;"ÿà"<=t[1].slice(0,2)&&t[1].slice(0,2)<="ÿï";)t=[t[0]].concat(t.slice(2));return t.join("")}(l.thumbnail)).length>64e3))throw new Error("Given thumbnail is too large. max 64kB");var T="",R="",_="",F="\0\0\0\0";if(c){var M=h(">L",[D=8+w]);T=h(">H",[34665])+h(">H",[m.Long])+h(">L",[1])+M}if(p){M=h(">L",[D=8+w+S]);R=h(">H",[34853])+h(">H",[m.Long])+h(">L",[1])+M}if(d){M=h(">L",[D=8+w+S+A]);_=h(">H",[40965])+h(">H",[m.Long])+h(">L",[1])+M}if(g){var D;F=h(">L",[D=8+w+S+A+N]);var O="\0\0\0\0"+h(">L",[D+b[0].length+24+4+b[1].length]),L="\0\0\0\0"+h(">L",[v.length]);C=b[0]+O+L+"\0\0\0\0"+b[1]+v}var P=x[0]+T+R+F+x[1];return c&&(k=y[0]+_+y[1]),"Exif\0\0MM\0*\0\0\0\b"+P+k+I+E+C},u.prototype={get_ifd:function(e,t){var n,r={},a=p(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],s=e+2;n=["0th","1st"].indexOf(t)>-1?"Image":t;for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("B",a),this.tiftag.slice(t,t+a))):n=p(this.endian_mark+d("B",a),s.slice(0,a));else if(2==r)a>4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a-1)):n=s.slice(0,a-1);else if(3==r)a>2?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("H",a),this.tiftag.slice(t,t+2*a))):n=p(this.endian_mark+d("H",a),s.slice(0,2*a));else if(4==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("L",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("L",a),s);else if(5==r)if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a)):n=s.slice(0,a);else if(9==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("l",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("l",a),s);else{if(10!=r)throw new Error("Exif might be wrong. Got incorrect value type to decode. type:"+r);if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(i=0;i>2,s=(3&t)<<4|(n=e.charCodeAt(l++))>>4,i=(15&n)<<2|(r=e.charCodeAt(l++))>>6,o=63&r,isNaN(n)?i=o=64:isNaN(r)&&(o=64),u=u+c.charAt(a)+c.charAt(s)+c.charAt(i)+c.charAt(o);return u};if("undefined"!=typeof window&&"function"==typeof window.atob)var c=window.atob;if(void 0===c)c=function(e){var t,n,r,a,s,i,o="",u=0,l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");u>4,n=(15&a)<<4|(s=l.indexOf(e.charAt(u++)))>>2,r=(3&s)<<6|(i=l.indexOf(e.charAt(u++))),o+=String.fromCharCode(t),64!=s&&(o+=String.fromCharCode(n)),64!=i&&(o+=String.fromCharCode(r));return o};function h(e,t){if(!(t instanceof Array))throw new Error("'pack' error. Got invalid type argument.");if(e.length-1!=t.length)throw new Error("'pack' error. "+(e.length-1)+" marks, "+t.length+" elements.");var n;if("<"==e[0])n=!0;else{if(">"!=e[0])throw new Error("");n=!1}for(var r="",a=1,s=null,i=null,o=null;i=e[a];){if("b"==i.toLowerCase()){if(s=t[a-1],"b"==i&&s<0&&(s+=256),s>255||s<0)throw new Error("'pack' error.");o=String.fromCharCode(s)}else if("H"==i){if((s=t[a-1])>65535||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}else{if("l"!=i.toLowerCase())throw new Error("'pack' error.");if(s=t[a-1],"l"==i&&s<0&&(s+=4294967296),s>4294967295||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s/16777216))+String.fromCharCode(Math.floor(s%16777216/65536))+String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}r+=o,a+=1}return r}function p(e,t){if("string"!=typeof t)throw new Error("'unpack' error. Got invalid type argument.");for(var n,r=0,a=1;a"!=e[0])throw new Error("'unpack' error.");n=!1}for(var s=[],i=0,o=1,u=null,l=null,c=null,h="";l=e[o];){if("b"==l.toLowerCase())c=1,u=(h=t.slice(i,i+c)).charCodeAt(0),"b"==l&&u>=128&&(u-=256);else if("H"==l)c=2,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=256*h.charCodeAt(0)+h.charCodeAt(1);else{if("l"!=l.toLowerCase())throw new Error("'unpack' error. "+l);c=4,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=16777216*h.charCodeAt(0)+65536*h.charCodeAt(1)+256*h.charCodeAt(2)+h.charCodeAt(3),"l"==l&&u>=2147483648&&(u-=4294967296)}s.push(u),i+=c,o+=1}return s}function d(e,t){for(var n="",r=0;rH",e.slice(t+2,t+4))[0]+2;if(n.push(e.slice(t,r)),(t=r)>=e.length)throw new Error("Wrong JPEG data.")}return n}var m={Byte:1,Ascii:2,Short:3,Long:4,Rational:5,Undefined:7,SLong:9,SRational:10},g={Image:{11:{name:"ProcessingSoftware",type:"Ascii"},254:{name:"NewSubfileType",type:"Long"},255:{name:"SubfileType",type:"Short"},256:{name:"ImageWidth",type:"Long"},257:{name:"ImageLength",type:"Long"},258:{name:"BitsPerSample",type:"Short"},259:{name:"Compression",type:"Short"},262:{name:"PhotometricInterpretation",type:"Short"},263:{name:"Threshholding",type:"Short"},264:{name:"CellWidth",type:"Short"},265:{name:"CellLength",type:"Short"},266:{name:"FillOrder",type:"Short"},269:{name:"DocumentName",type:"Ascii"},270:{name:"ImageDescription",type:"Ascii"},271:{name:"Make",type:"Ascii"},272:{name:"Model",type:"Ascii"},273:{name:"StripOffsets",type:"Long"},274:{name:"Orientation",type:"Short"},277:{name:"SamplesPerPixel",type:"Short"},278:{name:"RowsPerStrip",type:"Long"},279:{name:"StripByteCounts",type:"Long"},282:{name:"XResolution",type:"Rational"},283:{name:"YResolution",type:"Rational"},284:{name:"PlanarConfiguration",type:"Short"},290:{name:"GrayResponseUnit",type:"Short"},291:{name:"GrayResponseCurve",type:"Short"},292:{name:"T4Options",type:"Long"},293:{name:"T6Options",type:"Long"},296:{name:"ResolutionUnit",type:"Short"},301:{name:"TransferFunction",type:"Short"},305:{name:"Software",type:"Ascii"},306:{name:"DateTime",type:"Ascii"},315:{name:"Artist",type:"Ascii"},316:{name:"HostComputer",type:"Ascii"},317:{name:"Predictor",type:"Short"},318:{name:"WhitePoint",type:"Rational"},319:{name:"PrimaryChromaticities",type:"Rational"},320:{name:"ColorMap",type:"Short"},321:{name:"HalftoneHints",type:"Short"},322:{name:"TileWidth",type:"Short"},323:{name:"TileLength",type:"Short"},324:{name:"TileOffsets",type:"Short"},325:{name:"TileByteCounts",type:"Short"},330:{name:"SubIFDs",type:"Long"},332:{name:"InkSet",type:"Short"},333:{name:"InkNames",type:"Ascii"},334:{name:"NumberOfInks",type:"Short"},336:{name:"DotRange",type:"Byte"},337:{name:"TargetPrinter",type:"Ascii"},338:{name:"ExtraSamples",type:"Short"},339:{name:"SampleFormat",type:"Short"},340:{name:"SMinSampleValue",type:"Short"},341:{name:"SMaxSampleValue",type:"Short"},342:{name:"TransferRange",type:"Short"},343:{name:"ClipPath",type:"Byte"},344:{name:"XClipPathUnits",type:"Long"},345:{name:"YClipPathUnits",type:"Long"},346:{name:"Indexed",type:"Short"},347:{name:"JPEGTables",type:"Undefined"},351:{name:"OPIProxy",type:"Short"},512:{name:"JPEGProc",type:"Long"},513:{name:"JPEGInterchangeFormat",type:"Long"},514:{name:"JPEGInterchangeFormatLength",type:"Long"},515:{name:"JPEGRestartInterval",type:"Short"},517:{name:"JPEGLosslessPredictors",type:"Short"},518:{name:"JPEGPointTransforms",type:"Short"},519:{name:"JPEGQTables",type:"Long"},520:{name:"JPEGDCTables",type:"Long"},521:{name:"JPEGACTables",type:"Long"},529:{name:"YCbCrCoefficients",type:"Rational"},530:{name:"YCbCrSubSampling",type:"Short"},531:{name:"YCbCrPositioning",type:"Short"},532:{name:"ReferenceBlackWhite",type:"Rational"},700:{name:"XMLPacket",type:"Byte"},18246:{name:"Rating",type:"Short"},18249:{name:"RatingPercent",type:"Short"},32781:{name:"ImageID",type:"Ascii"},33421:{name:"CFARepeatPatternDim",type:"Short"},33422:{name:"CFAPattern",type:"Byte"},33423:{name:"BatteryLevel",type:"Rational"},33432:{name:"Copyright",type:"Ascii"},33434:{name:"ExposureTime",type:"Rational"},34377:{name:"ImageResources",type:"Byte"},34665:{name:"ExifTag",type:"Long"},34675:{name:"InterColorProfile",type:"Undefined"},34853:{name:"GPSTag",type:"Long"},34857:{name:"Interlace",type:"Short"},34858:{name:"TimeZoneOffset",type:"Long"},34859:{name:"SelfTimerMode",type:"Short"},37387:{name:"FlashEnergy",type:"Rational"},37388:{name:"SpatialFrequencyResponse",type:"Undefined"},37389:{name:"Noise",type:"Undefined"},37390:{name:"FocalPlaneXResolution",type:"Rational"},37391:{name:"FocalPlaneYResolution",type:"Rational"},37392:{name:"FocalPlaneResolutionUnit",type:"Short"},37393:{name:"ImageNumber",type:"Long"},37394:{name:"SecurityClassification",type:"Ascii"},37395:{name:"ImageHistory",type:"Ascii"},37397:{name:"ExposureIndex",type:"Rational"},37398:{name:"TIFFEPStandardID",type:"Byte"},37399:{name:"SensingMethod",type:"Short"},40091:{name:"XPTitle",type:"Byte"},40092:{name:"XPComment",type:"Byte"},40093:{name:"XPAuthor",type:"Byte"},40094:{name:"XPKeywords",type:"Byte"},40095:{name:"XPSubject",type:"Byte"},50341:{name:"PrintImageMatching",type:"Undefined"},50706:{name:"DNGVersion",type:"Byte"},50707:{name:"DNGBackwardVersion",type:"Byte"},50708:{name:"UniqueCameraModel",type:"Ascii"},50709:{name:"LocalizedCameraModel",type:"Byte"},50710:{name:"CFAPlaneColor",type:"Byte"},50711:{name:"CFALayout",type:"Short"},50712:{name:"LinearizationTable",type:"Short"},50713:{name:"BlackLevelRepeatDim",type:"Short"},50714:{name:"BlackLevel",type:"Rational"},50715:{name:"BlackLevelDeltaH",type:"SRational"},50716:{name:"BlackLevelDeltaV",type:"SRational"},50717:{name:"WhiteLevel",type:"Short"},50718:{name:"DefaultScale",type:"Rational"},50719:{name:"DefaultCropOrigin",type:"Short"},50720:{name:"DefaultCropSize",type:"Short"},50721:{name:"ColorMatrix1",type:"SRational"},50722:{name:"ColorMatrix2",type:"SRational"},50723:{name:"CameraCalibration1",type:"SRational"},50724:{name:"CameraCalibration2",type:"SRational"},50725:{name:"ReductionMatrix1",type:"SRational"},50726:{name:"ReductionMatrix2",type:"SRational"},50727:{name:"AnalogBalance",type:"Rational"},50728:{name:"AsShotNeutral",type:"Short"},50729:{name:"AsShotWhiteXY",type:"Rational"},50730:{name:"BaselineExposure",type:"SRational"},50731:{name:"BaselineNoise",type:"Rational"},50732:{name:"BaselineSharpness",type:"Rational"},50733:{name:"BayerGreenSplit",type:"Long"},50734:{name:"LinearResponseLimit",type:"Rational"},50735:{name:"CameraSerialNumber",type:"Ascii"},50736:{name:"LensInfo",type:"Rational"},50737:{name:"ChromaBlurRadius",type:"Rational"},50738:{name:"AntiAliasStrength",type:"Rational"},50739:{name:"ShadowScale",type:"SRational"},50740:{name:"DNGPrivateData",type:"Byte"},50741:{name:"MakerNoteSafety",type:"Short"},50778:{name:"CalibrationIlluminant1",type:"Short"},50779:{name:"CalibrationIlluminant2",type:"Short"},50780:{name:"BestQualityScale",type:"Rational"},50781:{name:"RawDataUniqueID",type:"Byte"},50827:{name:"OriginalRawFileName",type:"Byte"},50828:{name:"OriginalRawFileData",type:"Undefined"},50829:{name:"ActiveArea",type:"Short"},50830:{name:"MaskedAreas",type:"Short"},50831:{name:"AsShotICCProfile",type:"Undefined"},50832:{name:"AsShotPreProfileMatrix",type:"SRational"},50833:{name:"CurrentICCProfile",type:"Undefined"},50834:{name:"CurrentPreProfileMatrix",type:"SRational"},50879:{name:"ColorimetricReference",type:"Short"},50931:{name:"CameraCalibrationSignature",type:"Byte"},50932:{name:"ProfileCalibrationSignature",type:"Byte"},50934:{name:"AsShotProfileName",type:"Byte"},50935:{name:"NoiseReductionApplied",type:"Rational"},50936:{name:"ProfileName",type:"Byte"},50937:{name:"ProfileHueSatMapDims",type:"Long"},50938:{name:"ProfileHueSatMapData1",type:"Float"},50939:{name:"ProfileHueSatMapData2",type:"Float"},50940:{name:"ProfileToneCurve",type:"Float"},50941:{name:"ProfileEmbedPolicy",type:"Long"},50942:{name:"ProfileCopyright",type:"Byte"},50964:{name:"ForwardMatrix1",type:"SRational"},50965:{name:"ForwardMatrix2",type:"SRational"},50966:{name:"PreviewApplicationName",type:"Byte"},50967:{name:"PreviewApplicationVersion",type:"Byte"},50968:{name:"PreviewSettingsName",type:"Byte"},50969:{name:"PreviewSettingsDigest",type:"Byte"},50970:{name:"PreviewColorSpace",type:"Long"},50971:{name:"PreviewDateTime",type:"Ascii"},50972:{name:"RawImageDigest",type:"Undefined"},50973:{name:"OriginalRawFileDigest",type:"Undefined"},50974:{name:"SubTileBlockSize",type:"Long"},50975:{name:"RowInterleaveFactor",type:"Long"},50981:{name:"ProfileLookTableDims",type:"Long"},50982:{name:"ProfileLookTableData",type:"Float"},51008:{name:"OpcodeList1",type:"Undefined"},51009:{name:"OpcodeList2",type:"Undefined"},51022:{name:"OpcodeList3",type:"Undefined"}},Exif:{33434:{name:"ExposureTime",type:"Rational"},33437:{name:"FNumber",type:"Rational"},34850:{name:"ExposureProgram",type:"Short"},34852:{name:"SpectralSensitivity",type:"Ascii"},34855:{name:"ISOSpeedRatings",type:"Short"},34856:{name:"OECF",type:"Undefined"},34864:{name:"SensitivityType",type:"Short"},34865:{name:"StandardOutputSensitivity",type:"Long"},34866:{name:"RecommendedExposureIndex",type:"Long"},34867:{name:"ISOSpeed",type:"Long"},34868:{name:"ISOSpeedLatitudeyyy",type:"Long"},34869:{name:"ISOSpeedLatitudezzz",type:"Long"},36864:{name:"ExifVersion",type:"Undefined"},36867:{name:"DateTimeOriginal",type:"Ascii"},36868:{name:"DateTimeDigitized",type:"Ascii"},37121:{name:"ComponentsConfiguration",type:"Undefined"},37122:{name:"CompressedBitsPerPixel",type:"Rational"},37377:{name:"ShutterSpeedValue",type:"SRational"},37378:{name:"ApertureValue",type:"Rational"},37379:{name:"BrightnessValue",type:"SRational"},37380:{name:"ExposureBiasValue",type:"SRational"},37381:{name:"MaxApertureValue",type:"Rational"},37382:{name:"SubjectDistance",type:"Rational"},37383:{name:"MeteringMode",type:"Short"},37384:{name:"LightSource",type:"Short"},37385:{name:"Flash",type:"Short"},37386:{name:"FocalLength",type:"Rational"},37396:{name:"SubjectArea",type:"Short"},37500:{name:"MakerNote",type:"Undefined"},37510:{name:"UserComment",type:"Ascii"},37520:{name:"SubSecTime",type:"Ascii"},37521:{name:"SubSecTimeOriginal",type:"Ascii"},37522:{name:"SubSecTimeDigitized",type:"Ascii"},40960:{name:"FlashpixVersion",type:"Undefined"},40961:{name:"ColorSpace",type:"Short"},40962:{name:"PixelXDimension",type:"Long"},40963:{name:"PixelYDimension",type:"Long"},40964:{name:"RelatedSoundFile",type:"Ascii"},40965:{name:"InteroperabilityTag",type:"Long"},41483:{name:"FlashEnergy",type:"Rational"},41484:{name:"SpatialFrequencyResponse",type:"Undefined"},41486:{name:"FocalPlaneXResolution",type:"Rational"},41487:{name:"FocalPlaneYResolution",type:"Rational"},41488:{name:"FocalPlaneResolutionUnit",type:"Short"},41492:{name:"SubjectLocation",type:"Short"},41493:{name:"ExposureIndex",type:"Rational"},41495:{name:"SensingMethod",type:"Short"},41728:{name:"FileSource",type:"Undefined"},41729:{name:"SceneType",type:"Undefined"},41730:{name:"CFAPattern",type:"Undefined"},41985:{name:"CustomRendered",type:"Short"},41986:{name:"ExposureMode",type:"Short"},41987:{name:"WhiteBalance",type:"Short"},41988:{name:"DigitalZoomRatio",type:"Rational"},41989:{name:"FocalLengthIn35mmFilm",type:"Short"},41990:{name:"SceneCaptureType",type:"Short"},41991:{name:"GainControl",type:"Short"},41992:{name:"Contrast",type:"Short"},41993:{name:"Saturation",type:"Short"},41994:{name:"Sharpness",type:"Short"},41995:{name:"DeviceSettingDescription",type:"Undefined"},41996:{name:"SubjectDistanceRange",type:"Short"},42016:{name:"ImageUniqueID",type:"Ascii"},42032:{name:"CameraOwnerName",type:"Ascii"},42033:{name:"BodySerialNumber",type:"Ascii"},42034:{name:"LensSpecification",type:"Rational"},42035:{name:"LensMake",type:"Ascii"},42036:{name:"LensModel",type:"Ascii"},42037:{name:"LensSerialNumber",type:"Ascii"},42240:{name:"Gamma",type:"Rational"}},GPS:{0:{name:"GPSVersionID",type:"Byte"},1:{name:"GPSLatitudeRef",type:"Ascii"},2:{name:"GPSLatitude",type:"Rational"},3:{name:"GPSLongitudeRef",type:"Ascii"},4:{name:"GPSLongitude",type:"Rational"},5:{name:"GPSAltitudeRef",type:"Byte"},6:{name:"GPSAltitude",type:"Rational"},7:{name:"GPSTimeStamp",type:"Rational"},8:{name:"GPSSatellites",type:"Ascii"},9:{name:"GPSStatus",type:"Ascii"},10:{name:"GPSMeasureMode",type:"Ascii"},11:{name:"GPSDOP",type:"Rational"},12:{name:"GPSSpeedRef",type:"Ascii"},13:{name:"GPSSpeed",type:"Rational"},14:{name:"GPSTrackRef",type:"Ascii"},15:{name:"GPSTrack",type:"Rational"},16:{name:"GPSImgDirectionRef",type:"Ascii"},17:{name:"GPSImgDirection",type:"Rational"},18:{name:"GPSMapDatum",type:"Ascii"},19:{name:"GPSDestLatitudeRef",type:"Ascii"},20:{name:"GPSDestLatitude",type:"Rational"},21:{name:"GPSDestLongitudeRef",type:"Ascii"},22:{name:"GPSDestLongitude",type:"Rational"},23:{name:"GPSDestBearingRef",type:"Ascii"},24:{name:"GPSDestBearing",type:"Rational"},25:{name:"GPSDestDistanceRef",type:"Ascii"},26:{name:"GPSDestDistance",type:"Rational"},27:{name:"GPSProcessingMethod",type:"Undefined"},28:{name:"GPSAreaInformation",type:"Undefined"},29:{name:"GPSDateStamp",type:"Ascii"},30:{name:"GPSDifferential",type:"Short"},31:{name:"GPSHPositioningError",type:"Rational"}},Interop:{1:{name:"InteroperabilityIndex",type:"Ascii"}}};g["0th"]=g.Image,g["1st"]=g.Image,n.TAGS=g,n.ImageIFD={ProcessingSoftware:11,NewSubfileType:254,SubfileType:255,ImageWidth:256,ImageLength:257,BitsPerSample:258,Compression:259,PhotometricInterpretation:262,Threshholding:263,CellWidth:264,CellLength:265,FillOrder:266,DocumentName:269,ImageDescription:270,Make:271,Model:272,StripOffsets:273,Orientation:274,SamplesPerPixel:277,RowsPerStrip:278,StripByteCounts:279,XResolution:282,YResolution:283,PlanarConfiguration:284,GrayResponseUnit:290,GrayResponseCurve:291,T4Options:292,T6Options:293,ResolutionUnit:296,TransferFunction:301,Software:305,DateTime:306,Artist:315,HostComputer:316,Predictor:317,WhitePoint:318,PrimaryChromaticities:319,ColorMap:320,HalftoneHints:321,TileWidth:322,TileLength:323,TileOffsets:324,TileByteCounts:325,SubIFDs:330,InkSet:332,InkNames:333,NumberOfInks:334,DotRange:336,TargetPrinter:337,ExtraSamples:338,SampleFormat:339,SMinSampleValue:340,SMaxSampleValue:341,TransferRange:342,ClipPath:343,XClipPathUnits:344,YClipPathUnits:345,Indexed:346,JPEGTables:347,OPIProxy:351,JPEGProc:512,JPEGInterchangeFormat:513,JPEGInterchangeFormatLength:514,JPEGRestartInterval:515,JPEGLosslessPredictors:517,JPEGPointTransforms:518,JPEGQTables:519,JPEGDCTables:520,JPEGACTables:521,YCbCrCoefficients:529,YCbCrSubSampling:530,YCbCrPositioning:531,ReferenceBlackWhite:532,XMLPacket:700,Rating:18246,RatingPercent:18249,ImageID:32781,CFARepeatPatternDim:33421,CFAPattern:33422,BatteryLevel:33423,Copyright:33432,ExposureTime:33434,ImageResources:34377,ExifTag:34665,InterColorProfile:34675,GPSTag:34853,Interlace:34857,TimeZoneOffset:34858,SelfTimerMode:34859,FlashEnergy:37387,SpatialFrequencyResponse:37388,Noise:37389,FocalPlaneXResolution:37390,FocalPlaneYResolution:37391,FocalPlaneResolutionUnit:37392,ImageNumber:37393,SecurityClassification:37394,ImageHistory:37395,ExposureIndex:37397,TIFFEPStandardID:37398,SensingMethod:37399,XPTitle:40091,XPComment:40092,XPAuthor:40093,XPKeywords:40094,XPSubject:40095,PrintImageMatching:50341,DNGVersion:50706,DNGBackwardVersion:50707,UniqueCameraModel:50708,LocalizedCameraModel:50709,CFAPlaneColor:50710,CFALayout:50711,LinearizationTable:50712,BlackLevelRepeatDim:50713,BlackLevel:50714,BlackLevelDeltaH:50715,BlackLevelDeltaV:50716,WhiteLevel:50717,DefaultScale:50718,DefaultCropOrigin:50719,DefaultCropSize:50720,ColorMatrix1:50721,ColorMatrix2:50722,CameraCalibration1:50723,CameraCalibration2:50724,ReductionMatrix1:50725,ReductionMatrix2:50726,AnalogBalance:50727,AsShotNeutral:50728,AsShotWhiteXY:50729,BaselineExposure:50730,BaselineNoise:50731,BaselineSharpness:50732,BayerGreenSplit:50733,LinearResponseLimit:50734,CameraSerialNumber:50735,LensInfo:50736,ChromaBlurRadius:50737,AntiAliasStrength:50738,ShadowScale:50739,DNGPrivateData:50740,MakerNoteSafety:50741,CalibrationIlluminant1:50778,CalibrationIlluminant2:50779,BestQualityScale:50780,RawDataUniqueID:50781,OriginalRawFileName:50827,OriginalRawFileData:50828,ActiveArea:50829,MaskedAreas:50830,AsShotICCProfile:50831,AsShotPreProfileMatrix:50832,CurrentICCProfile:50833,CurrentPreProfileMatrix:50834,ColorimetricReference:50879,CameraCalibrationSignature:50931,ProfileCalibrationSignature:50932,AsShotProfileName:50934,NoiseReductionApplied:50935,ProfileName:50936,ProfileHueSatMapDims:50937,ProfileHueSatMapData1:50938,ProfileHueSatMapData2:50939,ProfileToneCurve:50940,ProfileEmbedPolicy:50941,ProfileCopyright:50942,ForwardMatrix1:50964,ForwardMatrix2:50965,PreviewApplicationName:50966,PreviewApplicationVersion:50967,PreviewSettingsName:50968,PreviewSettingsDigest:50969,PreviewColorSpace:50970,PreviewDateTime:50971,RawImageDigest:50972,OriginalRawFileDigest:50973,SubTileBlockSize:50974,RowInterleaveFactor:50975,ProfileLookTableDims:50981,ProfileLookTableData:50982,OpcodeList1:51008,OpcodeList2:51009,OpcodeList3:51022,NoiseProfile:51041},n.ExifIFD={ExposureTime:33434,FNumber:33437,ExposureProgram:34850,SpectralSensitivity:34852,ISOSpeedRatings:34855,OECF:34856,SensitivityType:34864,StandardOutputSensitivity:34865,RecommendedExposureIndex:34866,ISOSpeed:34867,ISOSpeedLatitudeyyy:34868,ISOSpeedLatitudezzz:34869,ExifVersion:36864,DateTimeOriginal:36867,DateTimeDigitized:36868,ComponentsConfiguration:37121,CompressedBitsPerPixel:37122,ShutterSpeedValue:37377,ApertureValue:37378,BrightnessValue:37379,ExposureBiasValue:37380,MaxApertureValue:37381,SubjectDistance:37382,MeteringMode:37383,LightSource:37384,Flash:37385,FocalLength:37386,SubjectArea:37396,MakerNote:37500,UserComment:37510,SubSecTime:37520,SubSecTimeOriginal:37521,SubSecTimeDigitized:37522,FlashpixVersion:40960,ColorSpace:40961,PixelXDimension:40962,PixelYDimension:40963,RelatedSoundFile:40964,InteroperabilityTag:40965,FlashEnergy:41483,SpatialFrequencyResponse:41484,FocalPlaneXResolution:41486,FocalPlaneYResolution:41487,FocalPlaneResolutionUnit:41488,SubjectLocation:41492,ExposureIndex:41493,SensingMethod:41495,FileSource:41728,SceneType:41729,CFAPattern:41730,CustomRendered:41985,ExposureMode:41986,WhiteBalance:41987,DigitalZoomRatio:41988,FocalLengthIn35mmFilm:41989,SceneCaptureType:41990,GainControl:41991,Contrast:41992,Saturation:41993,Sharpness:41994,DeviceSettingDescription:41995,SubjectDistanceRange:41996,ImageUniqueID:42016,CameraOwnerName:42032,BodySerialNumber:42033,LensSpecification:42034,LensMake:42035,LensModel:42036,LensSerialNumber:42037,Gamma:42240},n.GPSIFD={GPSVersionID:0,GPSLatitudeRef:1,GPSLatitude:2,GPSLongitudeRef:3,GPSLongitude:4,GPSAltitudeRef:5,GPSAltitude:6,GPSTimeStamp:7,GPSSatellites:8,GPSStatus:9,GPSMeasureMode:10,GPSDOP:11,GPSSpeedRef:12,GPSSpeed:13,GPSTrackRef:14,GPSTrack:15,GPSImgDirectionRef:16,GPSImgDirection:17,GPSMapDatum:18,GPSDestLatitudeRef:19,GPSDestLatitude:20,GPSDestLongitudeRef:21,GPSDestLongitude:22,GPSDestBearingRef:23,GPSDestBearing:24,GPSDestDistanceRef:25,GPSDestDistance:26,GPSProcessingMethod:27,GPSAreaInformation:28,GPSDateStamp:29,GPSDifferential:30,GPSHPositioningError:31},n.InteropIFD={InteroperabilityIndex:1},n.GPSHelper={degToDmsRational:function(e){var t=Math.abs(e),n=t%1*60,r=n%1*60;return[[Math.floor(t),1],[Math.floor(n),1],[Math.round(100*r),100]]},dmsRationalToDeg:function(e,t){var n="S"===t||"W"===t?-1:1;return(e[0][0]/e[0][1]+e[1][0]/e[1][1]/60+e[2][0]/e[2][1]/3600)*n}},e.exports&&(t=e.exports=n),t.piexif=n}()}));const Iq=async(e,t,n)=>{const r=await(e=>new Promise((t,n)=>{const r=new FileReader;r.onloadend=()=>t(r.result),r.readAsDataURL(e)}))(e),a=Sq.load(r),s=(await navigator.mediaDevices.enumerateDevices()).filter(e=>"videoinput"===e.kind).map(e=>e.label),i={width:n.width,height:n.height,usedCamera:t.label,camerasOnDevice:s},o={"0th":Object.assign(Object.assign({},a["0th"]),{[Sq.ImageIFD.Model]:i.usedCamera,[Sq.ImageIFD.ImageWidth]:i.width,[Sq.ImageIFD.ImageLength]:i.height}),Exif:Object.assign(Object.assign({},a.Exif),{[Sq.ExifIFD.UserComment]:JSON.stringify(i)}),GPS:Object.assign({},a.GPS),Interop:Object.assign({},a.Interop),"1st":Object.assign({},a["1st"]),thumbnail:a.thumbnail},u=Sq.dump(o),l=Sq.insert(u,r);return await fetch(l).then(e=>e.blob())},Aq=new Image;var Eq;Aq.src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjIyNC45OTk5OTk5OTk5OTk5NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHZlcnNpb249IjEuMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPGcgc3Ryb2tlPSJudWxsIiBpZD0iTGF5ZXIgMSI+CiAgIDxwYXRoIHN0cm9rZT0iIzRjYTU4NSIgaWQ9InN2Z18xIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBmaWxsPSJub25lIiBkPSJtNzQuMjc3NjUsNi45Mjc2MWMtMTEuMzc1OTcsLTAuMDE3MTMgLTMzLjU2NTUxLDUuMTA0MzMgLTQ2LjgxMzE2LDE5LjQ5NDgxYy02Ljc0MTQzLDcuMzIyOTIgLTE4LjEyMjY5LDIzLjA2OTY3IC0xOS4yNjc1OCw1OS42MTM2OWMtMC41MTkwNiwxNi41NjkyMSA1LjA0NTI0LDYwLjYyNTMzIDEwLjI0MDA2LDc2LjQ2Nzc1YzMuNjMxMywxMS4wNzQ2OCAyNy40ODIxNSw0My45MzM0OSA0NC40OTA2LDUzLjY4MjUxYzQuODA3OTEsMi43NTU0NiAxMS4yOTY2OCwyLjY4MjUxIDEyLjQyMjU1LDIuNjgyNTFjMS4xODg3NiwtMC4wODQ1NyA3LjMzMDI2LDAuMDcyOTQgMTIuMTM3NjUsLTIuNjgyNTFjMTcuMDA4NDYsLTkuNzQ5MDIgNDAuNDAyMDgsLTQyLjc2ODUxIDQ0LjQ5MDYsLTUzLjY4MjUxYzQuNDAwMzgsLTExLjc0NDkxIDEwLjc1OTY1LC01OS44OTg1NCAxMC4yNDAwNiwtNzYuNDY3NzVjLTEuMTQ0ODksLTM2LjU0NDAyIC0xMi41MjYxNSwtNTIuMjkwNzcgLTE5LjI2NzU4LC01OS42MTM2OWMtMTMuMjQ3NjUsLTE0LjM5MDQ4IC0zNS4zMDY2MywtMTkuNTI5MzMgLTQ2Ljc3ODI3LC0xOS40OTQ4MWMtMC43NDY4OCwwLjAwMjIyIC0xLjg5NDk0LDAgLTEuODk0OTQsMHoiIHN0cm9rZS13aWR0aD0iNy42NSIvPgogIDwvZz4KIDwvZz4KPC9zdmc+Cg==",function(e){e.JPEG="image/jpeg",e.PNG="image/png"}(Eq||(Eq={}));class Nq{constructor(e,t){this.showMask=!1,this.videoSize={width:0,height:0},this.streamPaused=!1,this.pauseStream=()=>{this.streamPaused=!0,this.videoElement.pause(),this.dropMask(),this.faceDetection&&kq.getInstance().stopDetector()},this.device=e,this.detector=kq.getInstance(this,e.isMobile,t)}setShowMask(e){this.showMask=e}setFaceDetection(e){this.faceDetection=e}setProbabilityThreshold(e){kq.getInstance().setProbabilityThreshold(e)}setCallbackErrors(e){this.callbackErrors=e}setCallbackAutoCapturing(e){this.callbackAutoCapturing=e}setCallbackFaceDetectionErrors(e){this.callbackFaceDetectionErrors=e}static getInstance(e,t){return Nq.instance||(Nq.instance=new Nq(e,t)),Nq.instance}returnErrors(e){this.callbackFaceDetectionErrors(e)}autoCapturing(){this.callbackAutoCapturing()}updateHtmlElements(e,t){this.videoElement=e,this.canvasElement=t,this.detector.updateHtmlElements(e)}async startDetection(){return this.detector.startDetector()}static orientationChange(){Nq.instance&&Nq.getInstance().drawMask()}startStream(e){this.stream&&this.stream.getTracks().forEach(e=>e.stop()),this.stream=e,"srcObject"in this.videoElement?this.videoElement.srcObject=e:this.videoElement.src=window.URL.createObjectURL(e),this.videoElement.play().then(()=>{this.streamPaused=!1,l.cameraReadyEvent(),this.drawMask(),this.faceDetection&&this.startDetection()})}async initStream(e){this.startStream(e)}async resumeStream(){this.streamPaused=!1,await this.videoElement.play(),this.drawMask(),this.faceDetection&&await kq.getInstance().startDetector()}updateCanvasSize(e){this.videoSize={width:this.videoElement.videoWidth,height:this.videoElement.videoHeight},e.width=this.videoSize.width,e.height=this.videoSize.height}dropStream(){this.streamStopped()||(this.stream.getTracks().forEach(e=>e.stop()),this.videoElement.srcObject=null),this.faceDetection&&kq.getInstance().stopDetector()}streamStopped(){return!(this.stream&&this.stream.getTracks&&this.stream.getTracks().length>0)}drawMask(){this.showMask&&!this.streamPaused&&setTimeout(()=>{this.updateCanvasSize(this.canvasElement);const e=this.canvasElement,t=e.getContext("2d"),n=e.width/Aq.width,r=e.height/Aq.height,a=Math.min(n,r),s=e.width{const t=document.createElement("canvas");t.width=this.videoElement.videoWidth,t.height=this.videoElement.videoHeight,e([await this.getFrame(t)])})}getFrame(e){return new Promise(t=>{e.getContext("2d").drawImage(this.videoElement,0,0,e.width,e.height),e.toBlob(e=>{if(e.type!==Eq.JPEG||this.device.isIos)t(e);else try{Iq(e,this.stream.getTracks()[0],this.videoSize).then(e=>t(e))}catch(n){t(e),this.callbackErrors(n,!1)}},Eq.PNG,1)})}}window.addEventListener("resize",Nq.orientationChange,!1),window.addEventListener("orientationchange",Nq.orientationChange,!1);let Cq=class{constructor(e){Object(u.f)(this,e),this.eventVideoStarted=Object(u.b)(this,"videoStarted",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.errorCameraEvent=Object(u.b)(this,"errorCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.callbackErrors=(e,t)=>{t?(this.errorCameraEvent.emit(e),this.eventCloseCamera.emit()):this.errorCameraEvent.emit(e)},this.callbackAutoCapturing=()=>{this.device.isMobile?this.eventMakePhoto.emit():this.eventTakePhoto.emit()},this.callbackFaceDetectionErrors=e=>{l.detectionError(e)}}componentDidLoad(){this.startStream()}render(){const e="camera "+(this.device.isMobile?"cameraMobile":"");return Object(u.d)("div",{class:e},Object(u.d)("video",{loop:!0,autoplay:!0,playsinline:!0,muted:!0,class:"cameraVideo",ref:e=>this.cameraVideo=e}),Object(u.d)("canvas",{class:"cameraCanvas",ref:e=>this.cameraCanvas=e}))}startStream(){Nq.instance||Nq.getInstance(this.device,this.modelPath);const e=Nq.getInstance();e.updateHtmlElements(this.cameraVideo,this.cameraCanvas),e.setShowMask(this.showMask),e.setFaceDetection(this.faceDetection),e.setProbabilityThreshold(this.probabilityThreshold),e.setCallbackErrors(this.callbackErrors),e.setCallbackAutoCapturing(this.callbackAutoCapturing),e.setCallbackFaceDetectionErrors(this.callbackFaceDetectionErrors)}};Cq.style=".camera{width:100%;height:100%;color:white;display:flex;align-items:center;justify-content:center;position:relative}.cameraCanvas{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);max-width:100%;max-height:100%;z-index:2}.cameraVideo{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);z-index:1;position:absolute;max-width:100%;max-height:100%}.cameraMobile{position:fixed;top:0;left:0;background:black}.canvas-on-video{max-width:100%;max-height:100%;position:absolute;left:50%;top:50%;z-index:2;transform:scale(-1, 1)}";let Tq=class{constructor(e){Object(u.f)(this,e),this.updateState=()=>{this._showMask="true"===this.show_mask,this._disable_control_panel="true"===this.disable_control_panel,this._face_detection="true"===this.face_detection,this._stopAfterCapturing="true"===this.stop_after_capturing,this._probabilityThreshold=this.probability_threshold?+this.probability_threshold:50,this.url_logo=this.url_logo?this.url_logo:"data:image/png;charset=utf-8;base64,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",this._debug="true"===this.debug,kq.debug=this._debug},this.photoIsReady=e=>{this._stopAfterCapturing&&this.closeCamera(),l.captureEvent(e)},this.enableButton=()=>{this._resolutionOnPhoto=!0},this.updateState(),this._cameraStatus=0,this._resolutionOnPhoto=!1,this._device=xq(),this._mobile=this._device.isMobile,this._mobileMakePhoto=!1}videoStarted(){this._resolutionOnPhoto=!0}async retakePhoto(){this._mobileMakePhoto=!1,await Nq.getInstance().resumeStream()}takePhoto(){Nq.getInstance().takePhoto().then(e=>{this.photoIsReady(e)})}async openCamera(){this._cameraStatus=1;const e=this._device.isMac?{audio:!1,video:{facingMode:"user",width:1920,height:1080}}:{audio:!1,video:{facingMode:"user",width:{ideal:1920},height:{ideal:1080}}};setTimeout(()=>{navigator.mediaDevices.getUserMedia(e).then(e=>{Nq.getInstance().initStream(e),this.videoStarted()}).catch(e=>{this.closeCamera(),l.errorEvent(e)})},100)}async loadModels(e){await kq.initDetector(e.detail.path)}errorCamera(e){l.errorEvent(e.detail.message)}closeCamera(){Nq.instance&&(this._cameraStatus=0,l.closeEvent(),Nq.getInstance().dropStream(),this._mobileMakePhoto=!1,this._resolutionOnPhoto=!1)}makePhoto(){this._mobile?(this._mobileMakePhoto=!0,Nq.getInstance().pauseStream()):this.takePhoto()}componentWillLoad(){l.init(this.component),navigator.mediaDevices||l.errorEvent("This browser does not support webRTC")}componentDidUpdate(){this.updateState()}render(){let e;return e=this._cameraStatus?Object(u.d)("camera-comp",{class:"block",showMask:this._showMask,device:this._device,faceDetection:this._face_detection,modelPath:this.model_path,probabilityThreshold:this._probabilityThreshold}):Object(u.d)("img",{src:this.url_logo,class:"logo",style:this.logo_style?JSON.parse(this.logo_style):"",alt:"logo"}),Object(u.d)("div",{class:"cameraContainer",id:"cameraContainer",style:{backgroundColor:this.background_color}},Object(u.d)("div",{class:"wrapperCamera",style:{height:this._disable_control_panel?"100%":"65%"}},e),Object(u.d)("control-panel",{class:"block",mobile:this._mobile,disableControlPanel:this._disable_control_panel,cameraStatus:this._cameraStatus,resolutionOnPhoto:this._resolutionOnPhoto,mobileMakePhoto:this._mobileMakePhoto,faceDetection:this._face_detection}))}get component(){return Object(u.c)(this)}};Tq.style=".cameraContainer{width:100%;height:100%;z-index:10;position:relative;overflow:hidden}.logo{max-height:450px;max-width:450px}.wrapperCamera{display:flex;justify-content:center;align-items:center}.block{width:100%;height:100%}@media screen and (orientation: portrait){.history{width:100vw;font-size:20px}@media screen and (max-height: 667px){.logo{background-size:120px;max-height:120px;max-width:120px}}@media screen and (min-height: 668px) and (max-height: 812px){.logo{background-size:140px;max-height:140px;max-width:140px}}@media (max-height: 667px){.logo{margin:0 auto}}}@media screen and (max-height: 414px){.logo{background-size:140px;max-height:140px;max-width:140px}}";const Rq=(e,t)=>[...t];let _q=class{constructor(e){Object(u.f)(this,e),this.eventOpenCamera=Object(u.b)(this,"openCamera",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventRetakePhoto=Object(u.b)(this,"retakePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.makePhoto=()=>{this.eventMakePhoto.emit()},this.closeCamera=()=>{this.eventCloseCamera.emit()},this.openCamera=()=>{this.eventOpenCamera.emit()},this.takePhoto=()=>{this.eventTakePhoto.emit()},this.retakePhoto=async()=>{this.eventRetakePhoto.emit()}}render(){return Object(u.d)("div",{class:"controlPanel"+(this.mobile?" controlMobile":"")},this.mobile?Object(u.d)("div",null,this.cameraStatus?Object(u.d)("div",null,this.mobileMakePhoto?Object(u.d)("div",null,Object(u.d)("div",{onClick:this.retakePhoto,class:"retake"},"retake"),Object(u.d)("img",{onClick:this.takePhoto,alt:"use this photo",class:"shoot takePhoto",src:"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMjEuMC4yLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDggNDg7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iOTZweCIgaGVpZ2h0PSI5NnB4Ij4KPHBhdGggc3R5bGU9ImZpbGw6I0M4RTZDOTsiIGQ9Ik00NCwyNGMwLDExLjA0NS04Ljk1NSwyMC0yMCwyMFM0LDM1LjA0NSw0LDI0UzEyLjk1NSw0LDI0LDRTNDQsMTIuOTU1LDQ0LDI0eiIvPgo8cGF0aCBzdHlsZT0iZmlsbDojNENBRjUwOyIgZD0iTTM0LjU4NiwxNC41ODZsLTEzLjU3LDEzLjU4NmwtNS42MDItNS41ODZsLTIuODI4LDIuODI4bDguNDM0LDguNDE0bDE2LjM5NS0xNi40MTRMMzQuNTg2LDE0LjU4NnoiLz4KPC9zdmc+Cg=="})):Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto,class:"shoot"}),Object(u.d)("div",{onClick:this.closeCamera,class:"close"},"close")):Object(u.d)("div",null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)("button",{onClick:this.openCamera},"Turn on camera"))):Object(u.d)(Rq,null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)(Rq,null,this.cameraStatus?Object(u.d)(Rq,null,Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto},"Capture"),Object(u.d)("button",{onClick:this.closeCamera,class:"cameraOff"},"Close camera")):Object(u.d)("button",{onClick:this.openCamera},"Open camera"))))}};_q.style='.controlPanel{height:35%;display:flex;justify-content:space-evenly;align-items:center;width:100%;max-width:450px;margin:auto}.buttons{width:100%;max-width:450px;display:flex;justify-content:space-evenly;align-items:center}button{width:164px;height:50px;border:none;margin-bottom:10px;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;color:#fff;font-family:"Avenir", Helvetica, sans-serif;font-weight:600;font-size:16px;background-color:#4ca585;outline:none;cursor:pointer}button[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.cameraOff{background-color:#667a87}.cameraOff:hover{background-color:#92a8b5}.shoot{width:50px;height:50px;border-radius:25px;border:2px solid white;outline:none;background-color:red;position:fixed;left:calc(50% - 25px);bottom:10px}.shoot[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.close{position:fixed;right:6vw;top:2vh;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.retake{position:fixed;right:6vw;bottom:35px;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.takePhoto{width:46px;height:46px;bottom:20px;background:none}@media screen and (orientation:landscape) and (min-width: 360px){.shoot{bottom:calc(50% - 25px);left:auto;right:5vw}}'}.call(this,"/index.js",n(124),"/",n(33),n(238).Buffer,n(242).setImmediate)},function(e,t,n){"use strict";(function(e){ /*! * The buffer module from node.js, for the browser. * diff --git a/public/acuant/11.9.3/AcuantPassiveLiveness.min.js b/public/acuant/11.9.3/AcuantPassiveLiveness.min.js index 776876f0a45..ccca92a942a 100644 --- a/public/acuant/11.9.3/AcuantPassiveLiveness.min.js +++ b/public/acuant/11.9.3/AcuantPassiveLiveness.min.js @@ -231,7 +231,7 @@ var fq=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?a * limitations under the License. * ============================================================================= */ -/** @license See the LICENSE file. */(e,{width:this.videoElement.videoWidth,height:this.videoElement.videoHeight}),n=new hq,r=this.checkNumberFaces(t);return n.FACE_NOT_FOUND=!r&&0===t.length,n.TOO_MANY_FACES=!r&&t.length>this.MAX_NUMBER_FACES,r&&(wq&&(n.FACE_ANGLE_TOO_LARGE=!this.checkHeadRotation(t)),n.PROBABILITY_TOO_SMALL=!this.checkProbability(t),n.FACE_TOO_SMALL=!this.checkFaceSize(t),n.FACE_CLOSE_TO_BORDER=!this.checkFaceIndent(t)),n}autoCapturing(){kq.debug&&console.info(this.counterSuccessfulResults),this.counterSuccessfulResults>=this.DEFAULT_NUMBER_SUCCESSFUL_RESULTS_FOR_AUTO_CAPTURING&&(this.stream.autoCapturing(),this.counterSuccessfulResults=0)}checkNumberFaces(e){return e.length===this.MAX_NUMBER_FACES}checkProbability(e){return e[0].detection.score>+this.probabilityThreshold/100}checkFaceSize(e){const t=e[0].detection.box,{width:n,height:r,area:a}=t,{imageHeight:s,imageWidth:i}=e[0].detection,o=100/(s*i/a);return Math.min(n/this.videoRatio,r/this.videoRatio)>(this.isMobile?this.MIN_FACE_SIZE_FOR_MOBILE:this.MIN_FACE_SIZE_FOR_DESKTOP)&&o>(this.isMobile?this.MIN_OCCUPIED_SPACE_FOR_MOBILE:this.MIN_OCCUPIED_SPACE_FOR_DESKTOP)}checkFaceIndent(e){const t=e[0].detection.box,{imageHeight:n,imageWidth:r}=e[0].detection,{top:a,left:s,bottom:i,right:o}=t,u=s,l=r-o,c=n-i;return!(athis.MAX_ANGLE_TURN_HEAD||-1*a[2]>this.MAX_ANGLE_TURN_HEAD?this.headTurnCounter++:(this.counterSuccessfulHeadTurns++,this.counterSuccessfulHeadTurns>=5&&(this.headTurnCounter=0,this.counterSuccessfulHeadTurns=0)),this.headTurnCounter<=1}drawFaces(e){this.innerCanvas||this.createCanvasForDrawingMask(this.videoElement);const t=this.innerCanvas;if(!t)return console.error("no canvas for drawing");const n=t.getContext("2d");if(n){n.clearRect(0,0,t.width,t.height),n.font='small-caps 20px "Segoe UI"',n.fillStyle="white";for(const t of e){n.lineWidth=3,n.strokeStyle="deepskyblue",n.fillStyle="deepskyblue",n.globalAlpha=.6,n.beginPath(),n.rect(t.detection.box.x,t.detection.box.y,t.detection.box.width,t.detection.box.height),n.stroke(),n.globalAlpha=1,n.globalAlpha=.8,n.fillStyle="lightblue";const e=2;for(let r=0;r"+d("B",e.length),e)}function a(e){return h(">"+d("H",e.length),e)}function s(e){return h(">"+d("L",e.length),e)}function i(e,t,n){var i,o,u,l,c="",p="";if("Byte"==t)(i=e.length)<=4?p=r(e)+d("\0",4-i):(p=h(">L",[n]),c=r(e));else if("Short"==t)(i=e.length)<=2?p=a(e)+d("\0\0",2-i):(p=h(">L",[n]),c=a(e));else if("Long"==t)(i=e.length)<=1?p=s(e):(p=h(">L",[n]),c=s(e));else if("Ascii"==t)(i=(o=e+"\0").length)>4?(p=h(">L",[n]),c=o):p=o+d("\0",4-i);else if("Rational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">L",[u])+h(">L",[l]);else{i=e.length,o="";for(var f=0;fL",[u])+h(">L",[l])}p=h(">L",[n]),c=o}else if("SRational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">l",[u])+h(">l",[l]);else{i=e.length,o="";for(f=0;fl",[u])+h(">l",[l])}p=h(">L",[n]),c=o}else"Undefined"==t&&((i=e.length)>4?(p=h(">L",[n]),c=e):p=e+d("\0",4-i));return[h(">L",[i]),p,c]}function o(e,t,n){var r,a=Object.keys(e).length,s=h(">H",[a]);r=["0th","1st"].indexOf(t)>-1?2+12*a+4:2+12*a;var o="",u="";for(var l in e)if("string"==typeof l&&(l=parseInt(l)),!("0th"==t&&[34665,34853].indexOf(l)>-1||"Exif"==t&&40965==l||"1st"==t&&[513,514].indexOf(l)>-1)){var c=e[l],p=h(">H",[l]),d=g[t][l].type,f=h(">H",[m[d]]);"number"==typeof c&&(c=[c]);var y=i(c,d,8+r+n+u.length);o+=p+f+y[0]+y[1],u+=y[2]}return[s+o,u]}function u(e){var t;if("ÿØ"==e.slice(0,2))t=function(e){for(var t,n=0;n-1)this.tiftag=e;else{if("Exif"!=e.slice(0,4))throw new Error("Given file is neither JPEG nor TIFF.");this.tiftag=e.slice(6)}}if(n.version="1.0.4",n.remove=function(e){var t=!1;if("ÿØ"==e.slice(0,2));else{if("data:image/jpeg;base64,"!=e.slice(0,23)&&"data:image/jpg;base64,"!=e.slice(0,22))throw new Error("Given data is not jpeg.");e=c(e.split(",")[1]),t=!0}var n=f(e).filter((function(e){return!("ÿá"==e.slice(0,2)&&"Exif\0\0"==e.slice(4,10))})).join("");return t&&(n="data:image/jpeg;base64,"+l(n)),n},n.insert=function(e,t){var n=!1;if("Exif\0\0"!=e.slice(0,6))throw new Error("Given data is not exif.");if("ÿØ"==t.slice(0,2));else{if("data:image/jpeg;base64,"!=t.slice(0,23)&&"data:image/jpg;base64,"!=t.slice(0,22))throw new Error("Given data is not jpeg.");t=c(t.split(",")[1]),n=!0}var r="ÿá"+h(">H",[e.length+2])+e,a=function(e,t){var n=!1,r=[];e.forEach((function(a,s){"ÿá"==a.slice(0,2)&&"Exif\0\0"==a.slice(4,10)&&(n?r.unshift(s):(e[s]=t,n=!0))})),r.forEach((function(t){e.splice(t,1)})),!n&&t&&(e=[e[0],t].concat(e.slice(1)));return e.join("")}(f(t),r);return n&&(a="data:image/jpeg;base64,"+l(a)),a},n.load=function(e){var t;if("string"!=typeof e)throw new Error("'load' gots invalid type argument.");if("ÿØ"==e.slice(0,2))t=e;else if("data:image/jpeg;base64,"==e.slice(0,23)||"data:image/jpg;base64,"==e.slice(0,22))t=c(e.split(",")[1]);else{if("Exif"!=e.slice(0,4))throw new Error("'load' gots invalid file data.");t=e.slice(6)}var n={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null},r=new u(t);if(null===r.tiftag)return n;"II"==r.tiftag.slice(0,2)?r.endian_mark="<":r.endian_mark=">";var a=p(r.endian_mark+"L",r.tiftag.slice(4,8))[0];n["0th"]=r.get_ifd(a,"0th");var s=n["0th"].first_ifd_pointer;if(delete n["0th"].first_ifd_pointer,34665 in n["0th"]&&(a=n["0th"][34665],n.Exif=r.get_ifd(a,"Exif")),34853 in n["0th"]&&(a=n["0th"][34853],n.GPS=r.get_ifd(a,"GPS")),40965 in n.Exif&&(a=n.Exif[40965],n.Interop=r.get_ifd(a,"Interop")),"\0\0\0\0"!=s&&(a=p(r.endian_mark+"L",s)[0],n["1st"]=r.get_ifd(a,"1st"),513 in n["1st"]&&514 in n["1st"])){var i=n["1st"][513]+n["1st"][514],o=r.tiftag.slice(n["1st"][513],i);n.thumbnail=o}return n},n.dump=function(e){var t,r,a,s,i,u,l=(t=e,JSON.parse(JSON.stringify(t))),c=!1,p=!1,d=!1,g=!1;r="0th"in l?l["0th"]:{},"Exif"in l&&Object.keys(l.Exif).length||"Interop"in l&&Object.keys(l.Interop).length?(r[34665]=1,c=!0,a=l.Exif,"Interop"in l&&Object.keys(l.Interop).length?(a[40965]=1,d=!0,s=l.Interop):Object.keys(a).indexOf(n.ExifIFD.InteroperabilityTag.toString())>-1&&delete a[40965]):Object.keys(r).indexOf(n.ImageIFD.ExifTag.toString())>-1&&delete r[34665],"GPS"in l&&Object.keys(l.GPS).length?(r[n.ImageIFD.GPSTag]=1,p=!0,i=l.GPS):Object.keys(r).indexOf(n.ImageIFD.GPSTag.toString())>-1&&delete r[n.ImageIFD.GPSTag],"1st"in l&&"thumbnail"in l&&null!=l.thumbnail&&(g=!0,l["1st"][513]=1,l["1st"][514]=1,u=l["1st"]);var y,b,v,x=o(r,"0th",0),w=x[0].length+12*c+12*p+4+x[1].length,k="",S=0,I="",A=0,E="",N=0,C="";(c&&(S=(y=o(a,"Exif",w))[0].length+12*d+y[1].length),p&&(A=(I=o(i,"GPS",w+S).join("")).length),d)&&(N=(E=o(s,"Interop",w+S+A).join("")).length);if(g&&(b=o(u,"1st",w+S+A+N),(v=function(e){var t=f(e);for(;"ÿà"<=t[1].slice(0,2)&&t[1].slice(0,2)<="ÿï";)t=[t[0]].concat(t.slice(2));return t.join("")}(l.thumbnail)).length>64e3))throw new Error("Given thumbnail is too large. max 64kB");var T="",R="",_="",F="\0\0\0\0";if(c){var M=h(">L",[D=8+w]);T=h(">H",[34665])+h(">H",[m.Long])+h(">L",[1])+M}if(p){M=h(">L",[D=8+w+S]);R=h(">H",[34853])+h(">H",[m.Long])+h(">L",[1])+M}if(d){M=h(">L",[D=8+w+S+A]);_=h(">H",[40965])+h(">H",[m.Long])+h(">L",[1])+M}if(g){var D;F=h(">L",[D=8+w+S+A+N]);var O="\0\0\0\0"+h(">L",[D+b[0].length+24+4+b[1].length]),L="\0\0\0\0"+h(">L",[v.length]);C=b[0]+O+L+"\0\0\0\0"+b[1]+v}var P=x[0]+T+R+F+x[1];return c&&(k=y[0]+_+y[1]),"Exif\0\0MM\0*\0\0\0\b"+P+k+I+E+C},u.prototype={get_ifd:function(e,t){var n,r={},a=p(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],s=e+2;n=["0th","1st"].indexOf(t)>-1?"Image":t;for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("B",a),this.tiftag.slice(t,t+a))):n=p(this.endian_mark+d("B",a),s.slice(0,a));else if(2==r)a>4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a-1)):n=s.slice(0,a-1);else if(3==r)a>2?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("H",a),this.tiftag.slice(t,t+2*a))):n=p(this.endian_mark+d("H",a),s.slice(0,2*a));else if(4==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("L",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("L",a),s);else if(5==r)if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a)):n=s.slice(0,a);else if(9==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("l",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("l",a),s);else{if(10!=r)throw new Error("Exif might be wrong. Got incorrect value type to decode. type:"+r);if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(i=0;i>2,s=(3&t)<<4|(n=e.charCodeAt(l++))>>4,i=(15&n)<<2|(r=e.charCodeAt(l++))>>6,o=63&r,isNaN(n)?i=o=64:isNaN(r)&&(o=64),u=u+c.charAt(a)+c.charAt(s)+c.charAt(i)+c.charAt(o);return u};if("undefined"!=typeof window&&"function"==typeof window.atob)var c=window.atob;if(void 0===c)c=function(e){var t,n,r,a,s,i,o="",u=0,l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");u>4,n=(15&a)<<4|(s=l.indexOf(e.charAt(u++)))>>2,r=(3&s)<<6|(i=l.indexOf(e.charAt(u++))),o+=String.fromCharCode(t),64!=s&&(o+=String.fromCharCode(n)),64!=i&&(o+=String.fromCharCode(r));return o};function h(e,t){if(!(t instanceof Array))throw new Error("'pack' error. Got invalid type argument.");if(e.length-1!=t.length)throw new Error("'pack' error. "+(e.length-1)+" marks, "+t.length+" elements.");var n;if("<"==e[0])n=!0;else{if(">"!=e[0])throw new Error("");n=!1}for(var r="",a=1,s=null,i=null,o=null;i=e[a];){if("b"==i.toLowerCase()){if(s=t[a-1],"b"==i&&s<0&&(s+=256),s>255||s<0)throw new Error("'pack' error.");o=String.fromCharCode(s)}else if("H"==i){if((s=t[a-1])>65535||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}else{if("l"!=i.toLowerCase())throw new Error("'pack' error.");if(s=t[a-1],"l"==i&&s<0&&(s+=4294967296),s>4294967295||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s/16777216))+String.fromCharCode(Math.floor(s%16777216/65536))+String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}r+=o,a+=1}return r}function p(e,t){if("string"!=typeof t)throw new Error("'unpack' error. Got invalid type argument.");for(var n,r=0,a=1;a"!=e[0])throw new Error("'unpack' error.");n=!1}for(var s=[],i=0,o=1,u=null,l=null,c=null,h="";l=e[o];){if("b"==l.toLowerCase())c=1,u=(h=t.slice(i,i+c)).charCodeAt(0),"b"==l&&u>=128&&(u-=256);else if("H"==l)c=2,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=256*h.charCodeAt(0)+h.charCodeAt(1);else{if("l"!=l.toLowerCase())throw new Error("'unpack' error. "+l);c=4,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=16777216*h.charCodeAt(0)+65536*h.charCodeAt(1)+256*h.charCodeAt(2)+h.charCodeAt(3),"l"==l&&u>=2147483648&&(u-=4294967296)}s.push(u),i+=c,o+=1}return s}function d(e,t){for(var n="",r=0;rH",e.slice(t+2,t+4))[0]+2;if(n.push(e.slice(t,r)),(t=r)>=e.length)throw new Error("Wrong JPEG data.")}return n}var m={Byte:1,Ascii:2,Short:3,Long:4,Rational:5,Undefined:7,SLong:9,SRational:10},g={Image:{11:{name:"ProcessingSoftware",type:"Ascii"},254:{name:"NewSubfileType",type:"Long"},255:{name:"SubfileType",type:"Short"},256:{name:"ImageWidth",type:"Long"},257:{name:"ImageLength",type:"Long"},258:{name:"BitsPerSample",type:"Short"},259:{name:"Compression",type:"Short"},262:{name:"PhotometricInterpretation",type:"Short"},263:{name:"Threshholding",type:"Short"},264:{name:"CellWidth",type:"Short"},265:{name:"CellLength",type:"Short"},266:{name:"FillOrder",type:"Short"},269:{name:"DocumentName",type:"Ascii"},270:{name:"ImageDescription",type:"Ascii"},271:{name:"Make",type:"Ascii"},272:{name:"Model",type:"Ascii"},273:{name:"StripOffsets",type:"Long"},274:{name:"Orientation",type:"Short"},277:{name:"SamplesPerPixel",type:"Short"},278:{name:"RowsPerStrip",type:"Long"},279:{name:"StripByteCounts",type:"Long"},282:{name:"XResolution",type:"Rational"},283:{name:"YResolution",type:"Rational"},284:{name:"PlanarConfiguration",type:"Short"},290:{name:"GrayResponseUnit",type:"Short"},291:{name:"GrayResponseCurve",type:"Short"},292:{name:"T4Options",type:"Long"},293:{name:"T6Options",type:"Long"},296:{name:"ResolutionUnit",type:"Short"},301:{name:"TransferFunction",type:"Short"},305:{name:"Software",type:"Ascii"},306:{name:"DateTime",type:"Ascii"},315:{name:"Artist",type:"Ascii"},316:{name:"HostComputer",type:"Ascii"},317:{name:"Predictor",type:"Short"},318:{name:"WhitePoint",type:"Rational"},319:{name:"PrimaryChromaticities",type:"Rational"},320:{name:"ColorMap",type:"Short"},321:{name:"HalftoneHints",type:"Short"},322:{name:"TileWidth",type:"Short"},323:{name:"TileLength",type:"Short"},324:{name:"TileOffsets",type:"Short"},325:{name:"TileByteCounts",type:"Short"},330:{name:"SubIFDs",type:"Long"},332:{name:"InkSet",type:"Short"},333:{name:"InkNames",type:"Ascii"},334:{name:"NumberOfInks",type:"Short"},336:{name:"DotRange",type:"Byte"},337:{name:"TargetPrinter",type:"Ascii"},338:{name:"ExtraSamples",type:"Short"},339:{name:"SampleFormat",type:"Short"},340:{name:"SMinSampleValue",type:"Short"},341:{name:"SMaxSampleValue",type:"Short"},342:{name:"TransferRange",type:"Short"},343:{name:"ClipPath",type:"Byte"},344:{name:"XClipPathUnits",type:"Long"},345:{name:"YClipPathUnits",type:"Long"},346:{name:"Indexed",type:"Short"},347:{name:"JPEGTables",type:"Undefined"},351:{name:"OPIProxy",type:"Short"},512:{name:"JPEGProc",type:"Long"},513:{name:"JPEGInterchangeFormat",type:"Long"},514:{name:"JPEGInterchangeFormatLength",type:"Long"},515:{name:"JPEGRestartInterval",type:"Short"},517:{name:"JPEGLosslessPredictors",type:"Short"},518:{name:"JPEGPointTransforms",type:"Short"},519:{name:"JPEGQTables",type:"Long"},520:{name:"JPEGDCTables",type:"Long"},521:{name:"JPEGACTables",type:"Long"},529:{name:"YCbCrCoefficients",type:"Rational"},530:{name:"YCbCrSubSampling",type:"Short"},531:{name:"YCbCrPositioning",type:"Short"},532:{name:"ReferenceBlackWhite",type:"Rational"},700:{name:"XMLPacket",type:"Byte"},18246:{name:"Rating",type:"Short"},18249:{name:"RatingPercent",type:"Short"},32781:{name:"ImageID",type:"Ascii"},33421:{name:"CFARepeatPatternDim",type:"Short"},33422:{name:"CFAPattern",type:"Byte"},33423:{name:"BatteryLevel",type:"Rational"},33432:{name:"Copyright",type:"Ascii"},33434:{name:"ExposureTime",type:"Rational"},34377:{name:"ImageResources",type:"Byte"},34665:{name:"ExifTag",type:"Long"},34675:{name:"InterColorProfile",type:"Undefined"},34853:{name:"GPSTag",type:"Long"},34857:{name:"Interlace",type:"Short"},34858:{name:"TimeZoneOffset",type:"Long"},34859:{name:"SelfTimerMode",type:"Short"},37387:{name:"FlashEnergy",type:"Rational"},37388:{name:"SpatialFrequencyResponse",type:"Undefined"},37389:{name:"Noise",type:"Undefined"},37390:{name:"FocalPlaneXResolution",type:"Rational"},37391:{name:"FocalPlaneYResolution",type:"Rational"},37392:{name:"FocalPlaneResolutionUnit",type:"Short"},37393:{name:"ImageNumber",type:"Long"},37394:{name:"SecurityClassification",type:"Ascii"},37395:{name:"ImageHistory",type:"Ascii"},37397:{name:"ExposureIndex",type:"Rational"},37398:{name:"TIFFEPStandardID",type:"Byte"},37399:{name:"SensingMethod",type:"Short"},40091:{name:"XPTitle",type:"Byte"},40092:{name:"XPComment",type:"Byte"},40093:{name:"XPAuthor",type:"Byte"},40094:{name:"XPKeywords",type:"Byte"},40095:{name:"XPSubject",type:"Byte"},50341:{name:"PrintImageMatching",type:"Undefined"},50706:{name:"DNGVersion",type:"Byte"},50707:{name:"DNGBackwardVersion",type:"Byte"},50708:{name:"UniqueCameraModel",type:"Ascii"},50709:{name:"LocalizedCameraModel",type:"Byte"},50710:{name:"CFAPlaneColor",type:"Byte"},50711:{name:"CFALayout",type:"Short"},50712:{name:"LinearizationTable",type:"Short"},50713:{name:"BlackLevelRepeatDim",type:"Short"},50714:{name:"BlackLevel",type:"Rational"},50715:{name:"BlackLevelDeltaH",type:"SRational"},50716:{name:"BlackLevelDeltaV",type:"SRational"},50717:{name:"WhiteLevel",type:"Short"},50718:{name:"DefaultScale",type:"Rational"},50719:{name:"DefaultCropOrigin",type:"Short"},50720:{name:"DefaultCropSize",type:"Short"},50721:{name:"ColorMatrix1",type:"SRational"},50722:{name:"ColorMatrix2",type:"SRational"},50723:{name:"CameraCalibration1",type:"SRational"},50724:{name:"CameraCalibration2",type:"SRational"},50725:{name:"ReductionMatrix1",type:"SRational"},50726:{name:"ReductionMatrix2",type:"SRational"},50727:{name:"AnalogBalance",type:"Rational"},50728:{name:"AsShotNeutral",type:"Short"},50729:{name:"AsShotWhiteXY",type:"Rational"},50730:{name:"BaselineExposure",type:"SRational"},50731:{name:"BaselineNoise",type:"Rational"},50732:{name:"BaselineSharpness",type:"Rational"},50733:{name:"BayerGreenSplit",type:"Long"},50734:{name:"LinearResponseLimit",type:"Rational"},50735:{name:"CameraSerialNumber",type:"Ascii"},50736:{name:"LensInfo",type:"Rational"},50737:{name:"ChromaBlurRadius",type:"Rational"},50738:{name:"AntiAliasStrength",type:"Rational"},50739:{name:"ShadowScale",type:"SRational"},50740:{name:"DNGPrivateData",type:"Byte"},50741:{name:"MakerNoteSafety",type:"Short"},50778:{name:"CalibrationIlluminant1",type:"Short"},50779:{name:"CalibrationIlluminant2",type:"Short"},50780:{name:"BestQualityScale",type:"Rational"},50781:{name:"RawDataUniqueID",type:"Byte"},50827:{name:"OriginalRawFileName",type:"Byte"},50828:{name:"OriginalRawFileData",type:"Undefined"},50829:{name:"ActiveArea",type:"Short"},50830:{name:"MaskedAreas",type:"Short"},50831:{name:"AsShotICCProfile",type:"Undefined"},50832:{name:"AsShotPreProfileMatrix",type:"SRational"},50833:{name:"CurrentICCProfile",type:"Undefined"},50834:{name:"CurrentPreProfileMatrix",type:"SRational"},50879:{name:"ColorimetricReference",type:"Short"},50931:{name:"CameraCalibrationSignature",type:"Byte"},50932:{name:"ProfileCalibrationSignature",type:"Byte"},50934:{name:"AsShotProfileName",type:"Byte"},50935:{name:"NoiseReductionApplied",type:"Rational"},50936:{name:"ProfileName",type:"Byte"},50937:{name:"ProfileHueSatMapDims",type:"Long"},50938:{name:"ProfileHueSatMapData1",type:"Float"},50939:{name:"ProfileHueSatMapData2",type:"Float"},50940:{name:"ProfileToneCurve",type:"Float"},50941:{name:"ProfileEmbedPolicy",type:"Long"},50942:{name:"ProfileCopyright",type:"Byte"},50964:{name:"ForwardMatrix1",type:"SRational"},50965:{name:"ForwardMatrix2",type:"SRational"},50966:{name:"PreviewApplicationName",type:"Byte"},50967:{name:"PreviewApplicationVersion",type:"Byte"},50968:{name:"PreviewSettingsName",type:"Byte"},50969:{name:"PreviewSettingsDigest",type:"Byte"},50970:{name:"PreviewColorSpace",type:"Long"},50971:{name:"PreviewDateTime",type:"Ascii"},50972:{name:"RawImageDigest",type:"Undefined"},50973:{name:"OriginalRawFileDigest",type:"Undefined"},50974:{name:"SubTileBlockSize",type:"Long"},50975:{name:"RowInterleaveFactor",type:"Long"},50981:{name:"ProfileLookTableDims",type:"Long"},50982:{name:"ProfileLookTableData",type:"Float"},51008:{name:"OpcodeList1",type:"Undefined"},51009:{name:"OpcodeList2",type:"Undefined"},51022:{name:"OpcodeList3",type:"Undefined"}},Exif:{33434:{name:"ExposureTime",type:"Rational"},33437:{name:"FNumber",type:"Rational"},34850:{name:"ExposureProgram",type:"Short"},34852:{name:"SpectralSensitivity",type:"Ascii"},34855:{name:"ISOSpeedRatings",type:"Short"},34856:{name:"OECF",type:"Undefined"},34864:{name:"SensitivityType",type:"Short"},34865:{name:"StandardOutputSensitivity",type:"Long"},34866:{name:"RecommendedExposureIndex",type:"Long"},34867:{name:"ISOSpeed",type:"Long"},34868:{name:"ISOSpeedLatitudeyyy",type:"Long"},34869:{name:"ISOSpeedLatitudezzz",type:"Long"},36864:{name:"ExifVersion",type:"Undefined"},36867:{name:"DateTimeOriginal",type:"Ascii"},36868:{name:"DateTimeDigitized",type:"Ascii"},37121:{name:"ComponentsConfiguration",type:"Undefined"},37122:{name:"CompressedBitsPerPixel",type:"Rational"},37377:{name:"ShutterSpeedValue",type:"SRational"},37378:{name:"ApertureValue",type:"Rational"},37379:{name:"BrightnessValue",type:"SRational"},37380:{name:"ExposureBiasValue",type:"SRational"},37381:{name:"MaxApertureValue",type:"Rational"},37382:{name:"SubjectDistance",type:"Rational"},37383:{name:"MeteringMode",type:"Short"},37384:{name:"LightSource",type:"Short"},37385:{name:"Flash",type:"Short"},37386:{name:"FocalLength",type:"Rational"},37396:{name:"SubjectArea",type:"Short"},37500:{name:"MakerNote",type:"Undefined"},37510:{name:"UserComment",type:"Ascii"},37520:{name:"SubSecTime",type:"Ascii"},37521:{name:"SubSecTimeOriginal",type:"Ascii"},37522:{name:"SubSecTimeDigitized",type:"Ascii"},40960:{name:"FlashpixVersion",type:"Undefined"},40961:{name:"ColorSpace",type:"Short"},40962:{name:"PixelXDimension",type:"Long"},40963:{name:"PixelYDimension",type:"Long"},40964:{name:"RelatedSoundFile",type:"Ascii"},40965:{name:"InteroperabilityTag",type:"Long"},41483:{name:"FlashEnergy",type:"Rational"},41484:{name:"SpatialFrequencyResponse",type:"Undefined"},41486:{name:"FocalPlaneXResolution",type:"Rational"},41487:{name:"FocalPlaneYResolution",type:"Rational"},41488:{name:"FocalPlaneResolutionUnit",type:"Short"},41492:{name:"SubjectLocation",type:"Short"},41493:{name:"ExposureIndex",type:"Rational"},41495:{name:"SensingMethod",type:"Short"},41728:{name:"FileSource",type:"Undefined"},41729:{name:"SceneType",type:"Undefined"},41730:{name:"CFAPattern",type:"Undefined"},41985:{name:"CustomRendered",type:"Short"},41986:{name:"ExposureMode",type:"Short"},41987:{name:"WhiteBalance",type:"Short"},41988:{name:"DigitalZoomRatio",type:"Rational"},41989:{name:"FocalLengthIn35mmFilm",type:"Short"},41990:{name:"SceneCaptureType",type:"Short"},41991:{name:"GainControl",type:"Short"},41992:{name:"Contrast",type:"Short"},41993:{name:"Saturation",type:"Short"},41994:{name:"Sharpness",type:"Short"},41995:{name:"DeviceSettingDescription",type:"Undefined"},41996:{name:"SubjectDistanceRange",type:"Short"},42016:{name:"ImageUniqueID",type:"Ascii"},42032:{name:"CameraOwnerName",type:"Ascii"},42033:{name:"BodySerialNumber",type:"Ascii"},42034:{name:"LensSpecification",type:"Rational"},42035:{name:"LensMake",type:"Ascii"},42036:{name:"LensModel",type:"Ascii"},42037:{name:"LensSerialNumber",type:"Ascii"},42240:{name:"Gamma",type:"Rational"}},GPS:{0:{name:"GPSVersionID",type:"Byte"},1:{name:"GPSLatitudeRef",type:"Ascii"},2:{name:"GPSLatitude",type:"Rational"},3:{name:"GPSLongitudeRef",type:"Ascii"},4:{name:"GPSLongitude",type:"Rational"},5:{name:"GPSAltitudeRef",type:"Byte"},6:{name:"GPSAltitude",type:"Rational"},7:{name:"GPSTimeStamp",type:"Rational"},8:{name:"GPSSatellites",type:"Ascii"},9:{name:"GPSStatus",type:"Ascii"},10:{name:"GPSMeasureMode",type:"Ascii"},11:{name:"GPSDOP",type:"Rational"},12:{name:"GPSSpeedRef",type:"Ascii"},13:{name:"GPSSpeed",type:"Rational"},14:{name:"GPSTrackRef",type:"Ascii"},15:{name:"GPSTrack",type:"Rational"},16:{name:"GPSImgDirectionRef",type:"Ascii"},17:{name:"GPSImgDirection",type:"Rational"},18:{name:"GPSMapDatum",type:"Ascii"},19:{name:"GPSDestLatitudeRef",type:"Ascii"},20:{name:"GPSDestLatitude",type:"Rational"},21:{name:"GPSDestLongitudeRef",type:"Ascii"},22:{name:"GPSDestLongitude",type:"Rational"},23:{name:"GPSDestBearingRef",type:"Ascii"},24:{name:"GPSDestBearing",type:"Rational"},25:{name:"GPSDestDistanceRef",type:"Ascii"},26:{name:"GPSDestDistance",type:"Rational"},27:{name:"GPSProcessingMethod",type:"Undefined"},28:{name:"GPSAreaInformation",type:"Undefined"},29:{name:"GPSDateStamp",type:"Ascii"},30:{name:"GPSDifferential",type:"Short"},31:{name:"GPSHPositioningError",type:"Rational"}},Interop:{1:{name:"InteroperabilityIndex",type:"Ascii"}}};g["0th"]=g.Image,g["1st"]=g.Image,n.TAGS=g,n.ImageIFD={ProcessingSoftware:11,NewSubfileType:254,SubfileType:255,ImageWidth:256,ImageLength:257,BitsPerSample:258,Compression:259,PhotometricInterpretation:262,Threshholding:263,CellWidth:264,CellLength:265,FillOrder:266,DocumentName:269,ImageDescription:270,Make:271,Model:272,StripOffsets:273,Orientation:274,SamplesPerPixel:277,RowsPerStrip:278,StripByteCounts:279,XResolution:282,YResolution:283,PlanarConfiguration:284,GrayResponseUnit:290,GrayResponseCurve:291,T4Options:292,T6Options:293,ResolutionUnit:296,TransferFunction:301,Software:305,DateTime:306,Artist:315,HostComputer:316,Predictor:317,WhitePoint:318,PrimaryChromaticities:319,ColorMap:320,HalftoneHints:321,TileWidth:322,TileLength:323,TileOffsets:324,TileByteCounts:325,SubIFDs:330,InkSet:332,InkNames:333,NumberOfInks:334,DotRange:336,TargetPrinter:337,ExtraSamples:338,SampleFormat:339,SMinSampleValue:340,SMaxSampleValue:341,TransferRange:342,ClipPath:343,XClipPathUnits:344,YClipPathUnits:345,Indexed:346,JPEGTables:347,OPIProxy:351,JPEGProc:512,JPEGInterchangeFormat:513,JPEGInterchangeFormatLength:514,JPEGRestartInterval:515,JPEGLosslessPredictors:517,JPEGPointTransforms:518,JPEGQTables:519,JPEGDCTables:520,JPEGACTables:521,YCbCrCoefficients:529,YCbCrSubSampling:530,YCbCrPositioning:531,ReferenceBlackWhite:532,XMLPacket:700,Rating:18246,RatingPercent:18249,ImageID:32781,CFARepeatPatternDim:33421,CFAPattern:33422,BatteryLevel:33423,Copyright:33432,ExposureTime:33434,ImageResources:34377,ExifTag:34665,InterColorProfile:34675,GPSTag:34853,Interlace:34857,TimeZoneOffset:34858,SelfTimerMode:34859,FlashEnergy:37387,SpatialFrequencyResponse:37388,Noise:37389,FocalPlaneXResolution:37390,FocalPlaneYResolution:37391,FocalPlaneResolutionUnit:37392,ImageNumber:37393,SecurityClassification:37394,ImageHistory:37395,ExposureIndex:37397,TIFFEPStandardID:37398,SensingMethod:37399,XPTitle:40091,XPComment:40092,XPAuthor:40093,XPKeywords:40094,XPSubject:40095,PrintImageMatching:50341,DNGVersion:50706,DNGBackwardVersion:50707,UniqueCameraModel:50708,LocalizedCameraModel:50709,CFAPlaneColor:50710,CFALayout:50711,LinearizationTable:50712,BlackLevelRepeatDim:50713,BlackLevel:50714,BlackLevelDeltaH:50715,BlackLevelDeltaV:50716,WhiteLevel:50717,DefaultScale:50718,DefaultCropOrigin:50719,DefaultCropSize:50720,ColorMatrix1:50721,ColorMatrix2:50722,CameraCalibration1:50723,CameraCalibration2:50724,ReductionMatrix1:50725,ReductionMatrix2:50726,AnalogBalance:50727,AsShotNeutral:50728,AsShotWhiteXY:50729,BaselineExposure:50730,BaselineNoise:50731,BaselineSharpness:50732,BayerGreenSplit:50733,LinearResponseLimit:50734,CameraSerialNumber:50735,LensInfo:50736,ChromaBlurRadius:50737,AntiAliasStrength:50738,ShadowScale:50739,DNGPrivateData:50740,MakerNoteSafety:50741,CalibrationIlluminant1:50778,CalibrationIlluminant2:50779,BestQualityScale:50780,RawDataUniqueID:50781,OriginalRawFileName:50827,OriginalRawFileData:50828,ActiveArea:50829,MaskedAreas:50830,AsShotICCProfile:50831,AsShotPreProfileMatrix:50832,CurrentICCProfile:50833,CurrentPreProfileMatrix:50834,ColorimetricReference:50879,CameraCalibrationSignature:50931,ProfileCalibrationSignature:50932,AsShotProfileName:50934,NoiseReductionApplied:50935,ProfileName:50936,ProfileHueSatMapDims:50937,ProfileHueSatMapData1:50938,ProfileHueSatMapData2:50939,ProfileToneCurve:50940,ProfileEmbedPolicy:50941,ProfileCopyright:50942,ForwardMatrix1:50964,ForwardMatrix2:50965,PreviewApplicationName:50966,PreviewApplicationVersion:50967,PreviewSettingsName:50968,PreviewSettingsDigest:50969,PreviewColorSpace:50970,PreviewDateTime:50971,RawImageDigest:50972,OriginalRawFileDigest:50973,SubTileBlockSize:50974,RowInterleaveFactor:50975,ProfileLookTableDims:50981,ProfileLookTableData:50982,OpcodeList1:51008,OpcodeList2:51009,OpcodeList3:51022,NoiseProfile:51041},n.ExifIFD={ExposureTime:33434,FNumber:33437,ExposureProgram:34850,SpectralSensitivity:34852,ISOSpeedRatings:34855,OECF:34856,SensitivityType:34864,StandardOutputSensitivity:34865,RecommendedExposureIndex:34866,ISOSpeed:34867,ISOSpeedLatitudeyyy:34868,ISOSpeedLatitudezzz:34869,ExifVersion:36864,DateTimeOriginal:36867,DateTimeDigitized:36868,ComponentsConfiguration:37121,CompressedBitsPerPixel:37122,ShutterSpeedValue:37377,ApertureValue:37378,BrightnessValue:37379,ExposureBiasValue:37380,MaxApertureValue:37381,SubjectDistance:37382,MeteringMode:37383,LightSource:37384,Flash:37385,FocalLength:37386,SubjectArea:37396,MakerNote:37500,UserComment:37510,SubSecTime:37520,SubSecTimeOriginal:37521,SubSecTimeDigitized:37522,FlashpixVersion:40960,ColorSpace:40961,PixelXDimension:40962,PixelYDimension:40963,RelatedSoundFile:40964,InteroperabilityTag:40965,FlashEnergy:41483,SpatialFrequencyResponse:41484,FocalPlaneXResolution:41486,FocalPlaneYResolution:41487,FocalPlaneResolutionUnit:41488,SubjectLocation:41492,ExposureIndex:41493,SensingMethod:41495,FileSource:41728,SceneType:41729,CFAPattern:41730,CustomRendered:41985,ExposureMode:41986,WhiteBalance:41987,DigitalZoomRatio:41988,FocalLengthIn35mmFilm:41989,SceneCaptureType:41990,GainControl:41991,Contrast:41992,Saturation:41993,Sharpness:41994,DeviceSettingDescription:41995,SubjectDistanceRange:41996,ImageUniqueID:42016,CameraOwnerName:42032,BodySerialNumber:42033,LensSpecification:42034,LensMake:42035,LensModel:42036,LensSerialNumber:42037,Gamma:42240},n.GPSIFD={GPSVersionID:0,GPSLatitudeRef:1,GPSLatitude:2,GPSLongitudeRef:3,GPSLongitude:4,GPSAltitudeRef:5,GPSAltitude:6,GPSTimeStamp:7,GPSSatellites:8,GPSStatus:9,GPSMeasureMode:10,GPSDOP:11,GPSSpeedRef:12,GPSSpeed:13,GPSTrackRef:14,GPSTrack:15,GPSImgDirectionRef:16,GPSImgDirection:17,GPSMapDatum:18,GPSDestLatitudeRef:19,GPSDestLatitude:20,GPSDestLongitudeRef:21,GPSDestLongitude:22,GPSDestBearingRef:23,GPSDestBearing:24,GPSDestDistanceRef:25,GPSDestDistance:26,GPSProcessingMethod:27,GPSAreaInformation:28,GPSDateStamp:29,GPSDifferential:30,GPSHPositioningError:31},n.InteropIFD={InteroperabilityIndex:1},n.GPSHelper={degToDmsRational:function(e){var t=Math.abs(e),n=t%1*60,r=n%1*60;return[[Math.floor(t),1],[Math.floor(n),1],[Math.round(100*r),100]]},dmsRationalToDeg:function(e,t){var n="S"===t||"W"===t?-1:1;return(e[0][0]/e[0][1]+e[1][0]/e[1][1]/60+e[2][0]/e[2][1]/3600)*n}},e.exports&&(t=e.exports=n),t.piexif=n}()}));const Iq=async(e,t,n)=>{const r=await(e=>new Promise((t,n)=>{const r=new FileReader;r.onloadend=()=>t(r.result),r.readAsDataURL(e)}))(e),a=Sq.load(r),s=(await navigator.mediaDevices.enumerateDevices()).filter(e=>"videoinput"===e.kind).map(e=>e.label),i={width:n.width,height:n.height,usedCamera:t.label,camerasOnDevice:s},o={"0th":Object.assign(Object.assign({},a["0th"]),{[Sq.ImageIFD.Model]:i.usedCamera,[Sq.ImageIFD.ImageWidth]:i.width,[Sq.ImageIFD.ImageLength]:i.height}),Exif:Object.assign(Object.assign({},a.Exif),{[Sq.ExifIFD.UserComment]:JSON.stringify(i)}),GPS:Object.assign({},a.GPS),Interop:Object.assign({},a.Interop),"1st":Object.assign({},a["1st"]),thumbnail:a.thumbnail},u=Sq.dump(o),l=Sq.insert(u,r);return await fetch(l).then(e=>e.blob())},Aq=new Image;var Eq;Aq.src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjIyNC45OTk5OTk5OTk5OTk5NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHZlcnNpb249IjEuMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPGcgc3Ryb2tlPSJudWxsIiBpZD0iTGF5ZXIgMSI+CiAgIDxwYXRoIHN0cm9rZT0iIzRjYTU4NSIgaWQ9InN2Z18xIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBmaWxsPSJub25lIiBkPSJtNzQuMjc3NjUsNi45Mjc2MWMtMTEuMzc1OTcsLTAuMDE3MTMgLTMzLjU2NTUxLDUuMTA0MzMgLTQ2LjgxMzE2LDE5LjQ5NDgxYy02Ljc0MTQzLDcuMzIyOTIgLTE4LjEyMjY5LDIzLjA2OTY3IC0xOS4yNjc1OCw1OS42MTM2OWMtMC41MTkwNiwxNi41NjkyMSA1LjA0NTI0LDYwLjYyNTMzIDEwLjI0MDA2LDc2LjQ2Nzc1YzMuNjMxMywxMS4wNzQ2OCAyNy40ODIxNSw0My45MzM0OSA0NC40OTA2LDUzLjY4MjUxYzQuODA3OTEsMi43NTU0NiAxMS4yOTY2OCwyLjY4MjUxIDEyLjQyMjU1LDIuNjgyNTFjMS4xODg3NiwtMC4wODQ1NyA3LjMzMDI2LDAuMDcyOTQgMTIuMTM3NjUsLTIuNjgyNTFjMTcuMDA4NDYsLTkuNzQ5MDIgNDAuNDAyMDgsLTQyLjc2ODUxIDQ0LjQ5MDYsLTUzLjY4MjUxYzQuNDAwMzgsLTExLjc0NDkxIDEwLjc1OTY1LC01OS44OTg1NCAxMC4yNDAwNiwtNzYuNDY3NzVjLTEuMTQ0ODksLTM2LjU0NDAyIC0xMi41MjYxNSwtNTIuMjkwNzcgLTE5LjI2NzU4LC01OS42MTM2OWMtMTMuMjQ3NjUsLTE0LjM5MDQ4IC0zNS4zMDY2MywtMTkuNTI5MzMgLTQ2Ljc3ODI3LC0xOS40OTQ4MWMtMC43NDY4OCwwLjAwMjIyIC0xLjg5NDk0LDAgLTEuODk0OTQsMHoiIHN0cm9rZS13aWR0aD0iNy42NSIvPgogIDwvZz4KIDwvZz4KPC9zdmc+Cg==",function(e){e.JPEG="image/jpeg",e.PNG="image/png"}(Eq||(Eq={}));class Nq{constructor(e,t){this.showMask=!1,this.videoSize={width:0,height:0},this.streamPaused=!1,this.pauseStream=()=>{this.streamPaused=!0,this.videoElement.pause(),this.dropMask(),this.faceDetection&&kq.getInstance().stopDetector()},this.device=e,this.detector=kq.getInstance(this,e.isMobile,t)}setShowMask(e){this.showMask=e}setFaceDetection(e){this.faceDetection=e}setProbabilityThreshold(e){kq.getInstance().setProbabilityThreshold(e)}setCallbackErrors(e){this.callbackErrors=e}setCallbackAutoCapturing(e){this.callbackAutoCapturing=e}setCallbackFaceDetectionErrors(e){this.callbackFaceDetectionErrors=e}static getInstance(e,t){return Nq.instance||(Nq.instance=new Nq(e,t)),Nq.instance}returnErrors(e){this.callbackFaceDetectionErrors(e)}autoCapturing(){this.callbackAutoCapturing()}updateHtmlElements(e,t){this.videoElement=e,this.canvasElement=t,this.detector.updateHtmlElements(e)}async startDetection(){return this.detector.startDetector()}static orientationChange(){Nq.instance&&Nq.getInstance().drawMask()}startStream(e){this.stream&&this.stream.getTracks().forEach(e=>e.stop()),this.stream=e,"srcObject"in this.videoElement?this.videoElement.srcObject=e:this.videoElement.src=window.URL.createObjectURL(e),this.videoElement.play().then(()=>{this.streamPaused=!1,l.cameraReadyEvent(),this.drawMask(),this.faceDetection&&this.startDetection()})}async initStream(e){this.startStream(e)}async resumeStream(){this.streamPaused=!1,await this.videoElement.play(),this.drawMask(),this.faceDetection&&await kq.getInstance().startDetector()}updateCanvasSize(e){this.videoSize={width:this.videoElement.videoWidth,height:this.videoElement.videoHeight},e.width=this.videoSize.width,e.height=this.videoSize.height}dropStream(){this.streamStopped()||(this.stream.getTracks().forEach(e=>e.stop()),this.videoElement.srcObject=null),this.faceDetection&&kq.getInstance().stopDetector()}streamStopped(){return!(this.stream&&this.stream.getTracks&&this.stream.getTracks().length>0)}drawMask(){this.showMask&&!this.streamPaused&&setTimeout(()=>{this.updateCanvasSize(this.canvasElement);const e=this.canvasElement,t=e.getContext("2d"),n=e.width/Aq.width,r=e.height/Aq.height,a=Math.min(n,r),s=e.width{const t=document.createElement("canvas");t.width=this.videoElement.videoWidth,t.height=this.videoElement.videoHeight,e([await this.getFrame(t)])})}getFrame(e){return new Promise(t=>{e.getContext("2d").drawImage(this.videoElement,0,0,e.width,e.height),e.toBlob(e=>{if(e.type!==Eq.JPEG||this.device.isIos)t(e);else try{Iq(e,this.stream.getTracks()[0],this.videoSize).then(e=>t(e))}catch(n){t(e),this.callbackErrors(n,!1)}},Eq.PNG,1)})}}window.addEventListener("resize",Nq.orientationChange,!1),window.addEventListener("orientationchange",Nq.orientationChange,!1);let Cq=class{constructor(e){Object(u.f)(this,e),this.eventVideoStarted=Object(u.b)(this,"videoStarted",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.errorCameraEvent=Object(u.b)(this,"errorCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.callbackErrors=(e,t)=>{t?(this.errorCameraEvent.emit(e),this.eventCloseCamera.emit()):this.errorCameraEvent.emit(e)},this.callbackAutoCapturing=()=>{this.device.isMobile?this.eventMakePhoto.emit():this.eventTakePhoto.emit()},this.callbackFaceDetectionErrors=e=>{l.detectionError(e)}}componentDidLoad(){this.startStream()}render(){const e="camera "+(this.device.isMobile?"cameraMobile":"");return Object(u.d)("div",{class:e},Object(u.d)("video",{loop:!0,autoplay:!0,playsinline:!0,muted:!0,class:"cameraVideo",ref:e=>this.cameraVideo=e}),Object(u.d)("canvas",{class:"cameraCanvas",ref:e=>this.cameraCanvas=e}))}startStream(){Nq.instance||Nq.getInstance(this.device,this.modelPath);const e=Nq.getInstance();e.updateHtmlElements(this.cameraVideo,this.cameraCanvas),e.setShowMask(this.showMask),e.setFaceDetection(this.faceDetection),e.setProbabilityThreshold(this.probabilityThreshold),e.setCallbackErrors(this.callbackErrors),e.setCallbackAutoCapturing(this.callbackAutoCapturing),e.setCallbackFaceDetectionErrors(this.callbackFaceDetectionErrors)}};Cq.style=".camera{width:100%;height:100%;color:white;display:flex;align-items:center;justify-content:center;position:relative}.cameraCanvas{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);max-width:100%;max-height:100%;z-index:2}.cameraVideo{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);z-index:1;position:absolute;max-width:100%;max-height:100%}.cameraMobile{position:fixed;top:0;left:0;background:black}.canvas-on-video{max-width:100%;max-height:100%;position:absolute;left:50%;top:50%;z-index:2;transform:scale(-1, 1)}";let Tq=class{constructor(e){Object(u.f)(this,e),this.updateState=()=>{this._showMask="true"===this.show_mask,this._disable_control_panel="true"===this.disable_control_panel,this._face_detection="true"===this.face_detection,this._stopAfterCapturing="true"===this.stop_after_capturing,this._probabilityThreshold=this.probability_threshold?+this.probability_threshold:50,this.url_logo=this.url_logo?this.url_logo:"data:image/png;charset=utf-8;base64,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",this._debug="true"===this.debug,kq.debug=this._debug},this.photoIsReady=e=>{this._stopAfterCapturing&&this.closeCamera(),l.captureEvent(e)},this.enableButton=()=>{this._resolutionOnPhoto=!0},this.updateState(),this._cameraStatus=0,this._resolutionOnPhoto=!1,this._device=xq(),this._mobile=this._device.isMobile,this._mobileMakePhoto=!1}videoStarted(){this._resolutionOnPhoto=!0}async retakePhoto(){this._mobileMakePhoto=!1,await Nq.getInstance().resumeStream()}takePhoto(){Nq.getInstance().takePhoto().then(e=>{this.photoIsReady(e)})}async openCamera(){this._cameraStatus=1;const e=this._device.isMac?{audio:!1,video:{facingMode:"user",width:1920,height:1080}}:{audio:!1,video:{facingMode:"user",width:{ideal:1920},height:{ideal:1080}}};setTimeout(()=>{navigator.mediaDevices.getUserMedia(e).then(e=>{Nq.getInstance().initStream(e),this.videoStarted()}).catch(e=>{this.closeCamera(),l.errorEvent(e)})},100)}async loadModels(e){await kq.initDetector(e.detail.path)}errorCamera(e){l.errorEvent(e.detail.message)}closeCamera(){Nq.instance&&(this._cameraStatus=0,l.closeEvent(),Nq.getInstance().dropStream(),this._mobileMakePhoto=!1,this._resolutionOnPhoto=!1)}makePhoto(){this._mobile?(this._mobileMakePhoto=!0,Nq.getInstance().pauseStream()):this.takePhoto()}componentWillLoad(){l.init(this.component),navigator.mediaDevices||l.errorEvent("This browser does not support webRTC")}componentDidUpdate(){this.updateState()}render(){let e;return e=this._cameraStatus?Object(u.d)("camera-comp",{class:"block",showMask:this._showMask,device:this._device,faceDetection:this._face_detection,modelPath:this.model_path,probabilityThreshold:this._probabilityThreshold}):Object(u.d)("img",{src:this.url_logo,class:"logo",style:this.logo_style?JSON.parse(this.logo_style):"",alt:"logo"}),Object(u.d)("div",{class:"cameraContainer",id:"cameraContainer",style:{backgroundColor:this.background_color}},Object(u.d)("div",{class:"wrapperCamera",style:{height:this._disable_control_panel?"100%":"65%"}},e),Object(u.d)("control-panel",{class:"block",mobile:this._mobile,disableControlPanel:this._disable_control_panel,cameraStatus:this._cameraStatus,resolutionOnPhoto:this._resolutionOnPhoto,mobileMakePhoto:this._mobileMakePhoto,faceDetection:this._face_detection}))}get component(){return Object(u.c)(this)}};Tq.style=".cameraContainer{width:100%;height:100%;z-index:10;position:relative;overflow:hidden}.logo{max-height:450px;max-width:450px}.wrapperCamera{display:flex;justify-content:center;align-items:center}.block{width:100%;height:100%}@media screen and (orientation: portrait){.history{width:100vw;font-size:20px}@media screen and (max-height: 667px){.logo{background-size:120px;max-height:120px;max-width:120px}}@media screen and (min-height: 668px) and (max-height: 812px){.logo{background-size:140px;max-height:140px;max-width:140px}}@media (max-height: 667px){.logo{margin:0 auto}}}@media screen and (max-height: 414px){.logo{background-size:140px;max-height:140px;max-width:140px}}";const Rq=(e,t)=>[...t];let _q=class{constructor(e){Object(u.f)(this,e),this.eventOpenCamera=Object(u.b)(this,"openCamera",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventRetakePhoto=Object(u.b)(this,"retakePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.makePhoto=()=>{this.eventMakePhoto.emit()},this.closeCamera=()=>{this.eventCloseCamera.emit()},this.openCamera=()=>{this.eventOpenCamera.emit()},this.takePhoto=()=>{this.eventTakePhoto.emit()},this.retakePhoto=async()=>{this.eventRetakePhoto.emit()}}render(){return Object(u.d)("div",{class:"controlPanel"+(this.mobile?" controlMobile":"")},this.mobile?Object(u.d)("div",null,this.cameraStatus?Object(u.d)("div",null,this.mobileMakePhoto?Object(u.d)("div",null,Object(u.d)("div",{onClick:this.retakePhoto,class:"retake"},"retake"),Object(u.d)("img",{onClick:this.takePhoto,class:"shoot takePhoto",src:"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMjEuMC4yLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDggNDg7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iOTZweCIgaGVpZ2h0PSI5NnB4Ij4KPHBhdGggc3R5bGU9ImZpbGw6I0M4RTZDOTsiIGQ9Ik00NCwyNGMwLDExLjA0NS04Ljk1NSwyMC0yMCwyMFM0LDM1LjA0NSw0LDI0UzEyLjk1NSw0LDI0LDRTNDQsMTIuOTU1LDQ0LDI0eiIvPgo8cGF0aCBzdHlsZT0iZmlsbDojNENBRjUwOyIgZD0iTTM0LjU4NiwxNC41ODZsLTEzLjU3LDEzLjU4NmwtNS42MDItNS41ODZsLTIuODI4LDIuODI4bDguNDM0LDguNDE0bDE2LjM5NS0xNi40MTRMMzQuNTg2LDE0LjU4NnoiLz4KPC9zdmc+Cg=="})):Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto,class:"shoot"}),Object(u.d)("div",{onClick:this.closeCamera,class:"close"},"close")):Object(u.d)("div",null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)("button",{onClick:this.openCamera},"Turn on camera"))):Object(u.d)(Rq,null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)(Rq,null,this.cameraStatus?Object(u.d)(Rq,null,Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto},"Capture"),Object(u.d)("button",{onClick:this.closeCamera,class:"cameraOff"},"Close camera")):Object(u.d)("button",{onClick:this.openCamera},"Open camera"))))}};_q.style='.controlPanel{height:35%;display:flex;justify-content:space-evenly;align-items:center;width:100%;max-width:450px;margin:auto}.buttons{width:100%;max-width:450px;display:flex;justify-content:space-evenly;align-items:center}button{width:164px;height:50px;border:none;margin-bottom:10px;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;color:#fff;font-family:"Avenir", Helvetica, sans-serif;font-weight:600;font-size:16px;background-color:#4ca585;outline:none;cursor:pointer}button[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.cameraOff{background-color:#667a87}.cameraOff:hover{background-color:#92a8b5}.shoot{width:50px;height:50px;border-radius:25px;border:2px solid white;outline:none;background-color:red;position:fixed;left:calc(50% - 25px);bottom:10px}.shoot[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.close{position:fixed;right:6vw;top:2vh;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.retake{position:fixed;right:6vw;bottom:35px;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.takePhoto{width:46px;height:46px;bottom:20px;background:none}@media screen and (orientation:landscape) and (min-width: 360px){.shoot{bottom:calc(50% - 25px);left:auto;right:5vw}}'}.call(this,"/index.js",n(77),"/",n(36),n(241).Buffer,n(245).setImmediate)},function(e,t,n){"use strict";(function(e){ +/** @license See the LICENSE file. */(e,{width:this.videoElement.videoWidth,height:this.videoElement.videoHeight}),n=new hq,r=this.checkNumberFaces(t);return n.FACE_NOT_FOUND=!r&&0===t.length,n.TOO_MANY_FACES=!r&&t.length>this.MAX_NUMBER_FACES,r&&(wq&&(n.FACE_ANGLE_TOO_LARGE=!this.checkHeadRotation(t)),n.PROBABILITY_TOO_SMALL=!this.checkProbability(t),n.FACE_TOO_SMALL=!this.checkFaceSize(t),n.FACE_CLOSE_TO_BORDER=!this.checkFaceIndent(t)),n}autoCapturing(){kq.debug&&console.info(this.counterSuccessfulResults),this.counterSuccessfulResults>=this.DEFAULT_NUMBER_SUCCESSFUL_RESULTS_FOR_AUTO_CAPTURING&&(this.stream.autoCapturing(),this.counterSuccessfulResults=0)}checkNumberFaces(e){return e.length===this.MAX_NUMBER_FACES}checkProbability(e){return e[0].detection.score>+this.probabilityThreshold/100}checkFaceSize(e){const t=e[0].detection.box,{width:n,height:r,area:a}=t,{imageHeight:s,imageWidth:i}=e[0].detection,o=100/(s*i/a);return Math.min(n/this.videoRatio,r/this.videoRatio)>(this.isMobile?this.MIN_FACE_SIZE_FOR_MOBILE:this.MIN_FACE_SIZE_FOR_DESKTOP)&&o>(this.isMobile?this.MIN_OCCUPIED_SPACE_FOR_MOBILE:this.MIN_OCCUPIED_SPACE_FOR_DESKTOP)}checkFaceIndent(e){const t=e[0].detection.box,{imageHeight:n,imageWidth:r}=e[0].detection,{top:a,left:s,bottom:i,right:o}=t,u=s,l=r-o,c=n-i;return!(athis.MAX_ANGLE_TURN_HEAD||-1*a[2]>this.MAX_ANGLE_TURN_HEAD?this.headTurnCounter++:(this.counterSuccessfulHeadTurns++,this.counterSuccessfulHeadTurns>=5&&(this.headTurnCounter=0,this.counterSuccessfulHeadTurns=0)),this.headTurnCounter<=1}drawFaces(e){this.innerCanvas||this.createCanvasForDrawingMask(this.videoElement);const t=this.innerCanvas;if(!t)return console.error("no canvas for drawing");const n=t.getContext("2d");if(n){n.clearRect(0,0,t.width,t.height),n.font='small-caps 20px "Segoe UI"',n.fillStyle="white";for(const t of e){n.lineWidth=3,n.strokeStyle="deepskyblue",n.fillStyle="deepskyblue",n.globalAlpha=.6,n.beginPath(),n.rect(t.detection.box.x,t.detection.box.y,t.detection.box.width,t.detection.box.height),n.stroke(),n.globalAlpha=1,n.globalAlpha=.8,n.fillStyle="lightblue";const e=2;for(let r=0;r"+d("B",e.length),e)}function a(e){return h(">"+d("H",e.length),e)}function s(e){return h(">"+d("L",e.length),e)}function i(e,t,n){var i,o,u,l,c="",p="";if("Byte"==t)(i=e.length)<=4?p=r(e)+d("\0",4-i):(p=h(">L",[n]),c=r(e));else if("Short"==t)(i=e.length)<=2?p=a(e)+d("\0\0",2-i):(p=h(">L",[n]),c=a(e));else if("Long"==t)(i=e.length)<=1?p=s(e):(p=h(">L",[n]),c=s(e));else if("Ascii"==t)(i=(o=e+"\0").length)>4?(p=h(">L",[n]),c=o):p=o+d("\0",4-i);else if("Rational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">L",[u])+h(">L",[l]);else{i=e.length,o="";for(var f=0;fL",[u])+h(">L",[l])}p=h(">L",[n]),c=o}else if("SRational"==t){if("number"==typeof e[0])i=1,u=e[0],l=e[1],o=h(">l",[u])+h(">l",[l]);else{i=e.length,o="";for(f=0;fl",[u])+h(">l",[l])}p=h(">L",[n]),c=o}else"Undefined"==t&&((i=e.length)>4?(p=h(">L",[n]),c=e):p=e+d("\0",4-i));return[h(">L",[i]),p,c]}function o(e,t,n){var r,a=Object.keys(e).length,s=h(">H",[a]);r=["0th","1st"].indexOf(t)>-1?2+12*a+4:2+12*a;var o="",u="";for(var l in e)if("string"==typeof l&&(l=parseInt(l)),!("0th"==t&&[34665,34853].indexOf(l)>-1||"Exif"==t&&40965==l||"1st"==t&&[513,514].indexOf(l)>-1)){var c=e[l],p=h(">H",[l]),d=g[t][l].type,f=h(">H",[m[d]]);"number"==typeof c&&(c=[c]);var y=i(c,d,8+r+n+u.length);o+=p+f+y[0]+y[1],u+=y[2]}return[s+o,u]}function u(e){var t;if("ÿØ"==e.slice(0,2))t=function(e){for(var t,n=0;n-1)this.tiftag=e;else{if("Exif"!=e.slice(0,4))throw new Error("Given file is neither JPEG nor TIFF.");this.tiftag=e.slice(6)}}if(n.version="1.0.4",n.remove=function(e){var t=!1;if("ÿØ"==e.slice(0,2));else{if("data:image/jpeg;base64,"!=e.slice(0,23)&&"data:image/jpg;base64,"!=e.slice(0,22))throw new Error("Given data is not jpeg.");e=c(e.split(",")[1]),t=!0}var n=f(e).filter((function(e){return!("ÿá"==e.slice(0,2)&&"Exif\0\0"==e.slice(4,10))})).join("");return t&&(n="data:image/jpeg;base64,"+l(n)),n},n.insert=function(e,t){var n=!1;if("Exif\0\0"!=e.slice(0,6))throw new Error("Given data is not exif.");if("ÿØ"==t.slice(0,2));else{if("data:image/jpeg;base64,"!=t.slice(0,23)&&"data:image/jpg;base64,"!=t.slice(0,22))throw new Error("Given data is not jpeg.");t=c(t.split(",")[1]),n=!0}var r="ÿá"+h(">H",[e.length+2])+e,a=function(e,t){var n=!1,r=[];e.forEach((function(a,s){"ÿá"==a.slice(0,2)&&"Exif\0\0"==a.slice(4,10)&&(n?r.unshift(s):(e[s]=t,n=!0))})),r.forEach((function(t){e.splice(t,1)})),!n&&t&&(e=[e[0],t].concat(e.slice(1)));return e.join("")}(f(t),r);return n&&(a="data:image/jpeg;base64,"+l(a)),a},n.load=function(e){var t;if("string"!=typeof e)throw new Error("'load' gots invalid type argument.");if("ÿØ"==e.slice(0,2))t=e;else if("data:image/jpeg;base64,"==e.slice(0,23)||"data:image/jpg;base64,"==e.slice(0,22))t=c(e.split(",")[1]);else{if("Exif"!=e.slice(0,4))throw new Error("'load' gots invalid file data.");t=e.slice(6)}var n={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null},r=new u(t);if(null===r.tiftag)return n;"II"==r.tiftag.slice(0,2)?r.endian_mark="<":r.endian_mark=">";var a=p(r.endian_mark+"L",r.tiftag.slice(4,8))[0];n["0th"]=r.get_ifd(a,"0th");var s=n["0th"].first_ifd_pointer;if(delete n["0th"].first_ifd_pointer,34665 in n["0th"]&&(a=n["0th"][34665],n.Exif=r.get_ifd(a,"Exif")),34853 in n["0th"]&&(a=n["0th"][34853],n.GPS=r.get_ifd(a,"GPS")),40965 in n.Exif&&(a=n.Exif[40965],n.Interop=r.get_ifd(a,"Interop")),"\0\0\0\0"!=s&&(a=p(r.endian_mark+"L",s)[0],n["1st"]=r.get_ifd(a,"1st"),513 in n["1st"]&&514 in n["1st"])){var i=n["1st"][513]+n["1st"][514],o=r.tiftag.slice(n["1st"][513],i);n.thumbnail=o}return n},n.dump=function(e){var t,r,a,s,i,u,l=(t=e,JSON.parse(JSON.stringify(t))),c=!1,p=!1,d=!1,g=!1;r="0th"in l?l["0th"]:{},"Exif"in l&&Object.keys(l.Exif).length||"Interop"in l&&Object.keys(l.Interop).length?(r[34665]=1,c=!0,a=l.Exif,"Interop"in l&&Object.keys(l.Interop).length?(a[40965]=1,d=!0,s=l.Interop):Object.keys(a).indexOf(n.ExifIFD.InteroperabilityTag.toString())>-1&&delete a[40965]):Object.keys(r).indexOf(n.ImageIFD.ExifTag.toString())>-1&&delete r[34665],"GPS"in l&&Object.keys(l.GPS).length?(r[n.ImageIFD.GPSTag]=1,p=!0,i=l.GPS):Object.keys(r).indexOf(n.ImageIFD.GPSTag.toString())>-1&&delete r[n.ImageIFD.GPSTag],"1st"in l&&"thumbnail"in l&&null!=l.thumbnail&&(g=!0,l["1st"][513]=1,l["1st"][514]=1,u=l["1st"]);var y,b,v,x=o(r,"0th",0),w=x[0].length+12*c+12*p+4+x[1].length,k="",S=0,I="",A=0,E="",N=0,C="";(c&&(S=(y=o(a,"Exif",w))[0].length+12*d+y[1].length),p&&(A=(I=o(i,"GPS",w+S).join("")).length),d)&&(N=(E=o(s,"Interop",w+S+A).join("")).length);if(g&&(b=o(u,"1st",w+S+A+N),(v=function(e){var t=f(e);for(;"ÿà"<=t[1].slice(0,2)&&t[1].slice(0,2)<="ÿï";)t=[t[0]].concat(t.slice(2));return t.join("")}(l.thumbnail)).length>64e3))throw new Error("Given thumbnail is too large. max 64kB");var T="",R="",_="",F="\0\0\0\0";if(c){var M=h(">L",[D=8+w]);T=h(">H",[34665])+h(">H",[m.Long])+h(">L",[1])+M}if(p){M=h(">L",[D=8+w+S]);R=h(">H",[34853])+h(">H",[m.Long])+h(">L",[1])+M}if(d){M=h(">L",[D=8+w+S+A]);_=h(">H",[40965])+h(">H",[m.Long])+h(">L",[1])+M}if(g){var D;F=h(">L",[D=8+w+S+A+N]);var O="\0\0\0\0"+h(">L",[D+b[0].length+24+4+b[1].length]),L="\0\0\0\0"+h(">L",[v.length]);C=b[0]+O+L+"\0\0\0\0"+b[1]+v}var P=x[0]+T+R+F+x[1];return c&&(k=y[0]+_+y[1]),"Exif\0\0MM\0*\0\0\0\b"+P+k+I+E+C},u.prototype={get_ifd:function(e,t){var n,r={},a=p(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],s=e+2;n=["0th","1st"].indexOf(t)>-1?"Image":t;for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("B",a),this.tiftag.slice(t,t+a))):n=p(this.endian_mark+d("B",a),s.slice(0,a));else if(2==r)a>4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a-1)):n=s.slice(0,a-1);else if(3==r)a>2?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("H",a),this.tiftag.slice(t,t+2*a))):n=p(this.endian_mark+d("H",a),s.slice(0,2*a));else if(4==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("L",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("L",a),s);else if(5==r)if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(var i=0;i4?(t=p(this.endian_mark+"L",s)[0],n=this.tiftag.slice(t,t+a)):n=s.slice(0,a);else if(9==r)a>1?(t=p(this.endian_mark+"L",s)[0],n=p(this.endian_mark+d("l",a),this.tiftag.slice(t,t+4*a))):n=p(this.endian_mark+d("l",a),s);else{if(10!=r)throw new Error("Exif might be wrong. Got incorrect value type to decode. type:"+r);if(t=p(this.endian_mark+"L",s)[0],a>1){n=[];for(i=0;i>2,s=(3&t)<<4|(n=e.charCodeAt(l++))>>4,i=(15&n)<<2|(r=e.charCodeAt(l++))>>6,o=63&r,isNaN(n)?i=o=64:isNaN(r)&&(o=64),u=u+c.charAt(a)+c.charAt(s)+c.charAt(i)+c.charAt(o);return u};if("undefined"!=typeof window&&"function"==typeof window.atob)var c=window.atob;if(void 0===c)c=function(e){var t,n,r,a,s,i,o="",u=0,l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");u>4,n=(15&a)<<4|(s=l.indexOf(e.charAt(u++)))>>2,r=(3&s)<<6|(i=l.indexOf(e.charAt(u++))),o+=String.fromCharCode(t),64!=s&&(o+=String.fromCharCode(n)),64!=i&&(o+=String.fromCharCode(r));return o};function h(e,t){if(!(t instanceof Array))throw new Error("'pack' error. Got invalid type argument.");if(e.length-1!=t.length)throw new Error("'pack' error. "+(e.length-1)+" marks, "+t.length+" elements.");var n;if("<"==e[0])n=!0;else{if(">"!=e[0])throw new Error("");n=!1}for(var r="",a=1,s=null,i=null,o=null;i=e[a];){if("b"==i.toLowerCase()){if(s=t[a-1],"b"==i&&s<0&&(s+=256),s>255||s<0)throw new Error("'pack' error.");o=String.fromCharCode(s)}else if("H"==i){if((s=t[a-1])>65535||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}else{if("l"!=i.toLowerCase())throw new Error("'pack' error.");if(s=t[a-1],"l"==i&&s<0&&(s+=4294967296),s>4294967295||s<0)throw new Error("'pack' error.");o=String.fromCharCode(Math.floor(s/16777216))+String.fromCharCode(Math.floor(s%16777216/65536))+String.fromCharCode(Math.floor(s%65536/256))+String.fromCharCode(s%256),n&&(o=o.split("").reverse().join(""))}r+=o,a+=1}return r}function p(e,t){if("string"!=typeof t)throw new Error("'unpack' error. Got invalid type argument.");for(var n,r=0,a=1;a"!=e[0])throw new Error("'unpack' error.");n=!1}for(var s=[],i=0,o=1,u=null,l=null,c=null,h="";l=e[o];){if("b"==l.toLowerCase())c=1,u=(h=t.slice(i,i+c)).charCodeAt(0),"b"==l&&u>=128&&(u-=256);else if("H"==l)c=2,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=256*h.charCodeAt(0)+h.charCodeAt(1);else{if("l"!=l.toLowerCase())throw new Error("'unpack' error. "+l);c=4,h=t.slice(i,i+c),n&&(h=h.split("").reverse().join("")),u=16777216*h.charCodeAt(0)+65536*h.charCodeAt(1)+256*h.charCodeAt(2)+h.charCodeAt(3),"l"==l&&u>=2147483648&&(u-=4294967296)}s.push(u),i+=c,o+=1}return s}function d(e,t){for(var n="",r=0;rH",e.slice(t+2,t+4))[0]+2;if(n.push(e.slice(t,r)),(t=r)>=e.length)throw new Error("Wrong JPEG data.")}return n}var m={Byte:1,Ascii:2,Short:3,Long:4,Rational:5,Undefined:7,SLong:9,SRational:10},g={Image:{11:{name:"ProcessingSoftware",type:"Ascii"},254:{name:"NewSubfileType",type:"Long"},255:{name:"SubfileType",type:"Short"},256:{name:"ImageWidth",type:"Long"},257:{name:"ImageLength",type:"Long"},258:{name:"BitsPerSample",type:"Short"},259:{name:"Compression",type:"Short"},262:{name:"PhotometricInterpretation",type:"Short"},263:{name:"Threshholding",type:"Short"},264:{name:"CellWidth",type:"Short"},265:{name:"CellLength",type:"Short"},266:{name:"FillOrder",type:"Short"},269:{name:"DocumentName",type:"Ascii"},270:{name:"ImageDescription",type:"Ascii"},271:{name:"Make",type:"Ascii"},272:{name:"Model",type:"Ascii"},273:{name:"StripOffsets",type:"Long"},274:{name:"Orientation",type:"Short"},277:{name:"SamplesPerPixel",type:"Short"},278:{name:"RowsPerStrip",type:"Long"},279:{name:"StripByteCounts",type:"Long"},282:{name:"XResolution",type:"Rational"},283:{name:"YResolution",type:"Rational"},284:{name:"PlanarConfiguration",type:"Short"},290:{name:"GrayResponseUnit",type:"Short"},291:{name:"GrayResponseCurve",type:"Short"},292:{name:"T4Options",type:"Long"},293:{name:"T6Options",type:"Long"},296:{name:"ResolutionUnit",type:"Short"},301:{name:"TransferFunction",type:"Short"},305:{name:"Software",type:"Ascii"},306:{name:"DateTime",type:"Ascii"},315:{name:"Artist",type:"Ascii"},316:{name:"HostComputer",type:"Ascii"},317:{name:"Predictor",type:"Short"},318:{name:"WhitePoint",type:"Rational"},319:{name:"PrimaryChromaticities",type:"Rational"},320:{name:"ColorMap",type:"Short"},321:{name:"HalftoneHints",type:"Short"},322:{name:"TileWidth",type:"Short"},323:{name:"TileLength",type:"Short"},324:{name:"TileOffsets",type:"Short"},325:{name:"TileByteCounts",type:"Short"},330:{name:"SubIFDs",type:"Long"},332:{name:"InkSet",type:"Short"},333:{name:"InkNames",type:"Ascii"},334:{name:"NumberOfInks",type:"Short"},336:{name:"DotRange",type:"Byte"},337:{name:"TargetPrinter",type:"Ascii"},338:{name:"ExtraSamples",type:"Short"},339:{name:"SampleFormat",type:"Short"},340:{name:"SMinSampleValue",type:"Short"},341:{name:"SMaxSampleValue",type:"Short"},342:{name:"TransferRange",type:"Short"},343:{name:"ClipPath",type:"Byte"},344:{name:"XClipPathUnits",type:"Long"},345:{name:"YClipPathUnits",type:"Long"},346:{name:"Indexed",type:"Short"},347:{name:"JPEGTables",type:"Undefined"},351:{name:"OPIProxy",type:"Short"},512:{name:"JPEGProc",type:"Long"},513:{name:"JPEGInterchangeFormat",type:"Long"},514:{name:"JPEGInterchangeFormatLength",type:"Long"},515:{name:"JPEGRestartInterval",type:"Short"},517:{name:"JPEGLosslessPredictors",type:"Short"},518:{name:"JPEGPointTransforms",type:"Short"},519:{name:"JPEGQTables",type:"Long"},520:{name:"JPEGDCTables",type:"Long"},521:{name:"JPEGACTables",type:"Long"},529:{name:"YCbCrCoefficients",type:"Rational"},530:{name:"YCbCrSubSampling",type:"Short"},531:{name:"YCbCrPositioning",type:"Short"},532:{name:"ReferenceBlackWhite",type:"Rational"},700:{name:"XMLPacket",type:"Byte"},18246:{name:"Rating",type:"Short"},18249:{name:"RatingPercent",type:"Short"},32781:{name:"ImageID",type:"Ascii"},33421:{name:"CFARepeatPatternDim",type:"Short"},33422:{name:"CFAPattern",type:"Byte"},33423:{name:"BatteryLevel",type:"Rational"},33432:{name:"Copyright",type:"Ascii"},33434:{name:"ExposureTime",type:"Rational"},34377:{name:"ImageResources",type:"Byte"},34665:{name:"ExifTag",type:"Long"},34675:{name:"InterColorProfile",type:"Undefined"},34853:{name:"GPSTag",type:"Long"},34857:{name:"Interlace",type:"Short"},34858:{name:"TimeZoneOffset",type:"Long"},34859:{name:"SelfTimerMode",type:"Short"},37387:{name:"FlashEnergy",type:"Rational"},37388:{name:"SpatialFrequencyResponse",type:"Undefined"},37389:{name:"Noise",type:"Undefined"},37390:{name:"FocalPlaneXResolution",type:"Rational"},37391:{name:"FocalPlaneYResolution",type:"Rational"},37392:{name:"FocalPlaneResolutionUnit",type:"Short"},37393:{name:"ImageNumber",type:"Long"},37394:{name:"SecurityClassification",type:"Ascii"},37395:{name:"ImageHistory",type:"Ascii"},37397:{name:"ExposureIndex",type:"Rational"},37398:{name:"TIFFEPStandardID",type:"Byte"},37399:{name:"SensingMethod",type:"Short"},40091:{name:"XPTitle",type:"Byte"},40092:{name:"XPComment",type:"Byte"},40093:{name:"XPAuthor",type:"Byte"},40094:{name:"XPKeywords",type:"Byte"},40095:{name:"XPSubject",type:"Byte"},50341:{name:"PrintImageMatching",type:"Undefined"},50706:{name:"DNGVersion",type:"Byte"},50707:{name:"DNGBackwardVersion",type:"Byte"},50708:{name:"UniqueCameraModel",type:"Ascii"},50709:{name:"LocalizedCameraModel",type:"Byte"},50710:{name:"CFAPlaneColor",type:"Byte"},50711:{name:"CFALayout",type:"Short"},50712:{name:"LinearizationTable",type:"Short"},50713:{name:"BlackLevelRepeatDim",type:"Short"},50714:{name:"BlackLevel",type:"Rational"},50715:{name:"BlackLevelDeltaH",type:"SRational"},50716:{name:"BlackLevelDeltaV",type:"SRational"},50717:{name:"WhiteLevel",type:"Short"},50718:{name:"DefaultScale",type:"Rational"},50719:{name:"DefaultCropOrigin",type:"Short"},50720:{name:"DefaultCropSize",type:"Short"},50721:{name:"ColorMatrix1",type:"SRational"},50722:{name:"ColorMatrix2",type:"SRational"},50723:{name:"CameraCalibration1",type:"SRational"},50724:{name:"CameraCalibration2",type:"SRational"},50725:{name:"ReductionMatrix1",type:"SRational"},50726:{name:"ReductionMatrix2",type:"SRational"},50727:{name:"AnalogBalance",type:"Rational"},50728:{name:"AsShotNeutral",type:"Short"},50729:{name:"AsShotWhiteXY",type:"Rational"},50730:{name:"BaselineExposure",type:"SRational"},50731:{name:"BaselineNoise",type:"Rational"},50732:{name:"BaselineSharpness",type:"Rational"},50733:{name:"BayerGreenSplit",type:"Long"},50734:{name:"LinearResponseLimit",type:"Rational"},50735:{name:"CameraSerialNumber",type:"Ascii"},50736:{name:"LensInfo",type:"Rational"},50737:{name:"ChromaBlurRadius",type:"Rational"},50738:{name:"AntiAliasStrength",type:"Rational"},50739:{name:"ShadowScale",type:"SRational"},50740:{name:"DNGPrivateData",type:"Byte"},50741:{name:"MakerNoteSafety",type:"Short"},50778:{name:"CalibrationIlluminant1",type:"Short"},50779:{name:"CalibrationIlluminant2",type:"Short"},50780:{name:"BestQualityScale",type:"Rational"},50781:{name:"RawDataUniqueID",type:"Byte"},50827:{name:"OriginalRawFileName",type:"Byte"},50828:{name:"OriginalRawFileData",type:"Undefined"},50829:{name:"ActiveArea",type:"Short"},50830:{name:"MaskedAreas",type:"Short"},50831:{name:"AsShotICCProfile",type:"Undefined"},50832:{name:"AsShotPreProfileMatrix",type:"SRational"},50833:{name:"CurrentICCProfile",type:"Undefined"},50834:{name:"CurrentPreProfileMatrix",type:"SRational"},50879:{name:"ColorimetricReference",type:"Short"},50931:{name:"CameraCalibrationSignature",type:"Byte"},50932:{name:"ProfileCalibrationSignature",type:"Byte"},50934:{name:"AsShotProfileName",type:"Byte"},50935:{name:"NoiseReductionApplied",type:"Rational"},50936:{name:"ProfileName",type:"Byte"},50937:{name:"ProfileHueSatMapDims",type:"Long"},50938:{name:"ProfileHueSatMapData1",type:"Float"},50939:{name:"ProfileHueSatMapData2",type:"Float"},50940:{name:"ProfileToneCurve",type:"Float"},50941:{name:"ProfileEmbedPolicy",type:"Long"},50942:{name:"ProfileCopyright",type:"Byte"},50964:{name:"ForwardMatrix1",type:"SRational"},50965:{name:"ForwardMatrix2",type:"SRational"},50966:{name:"PreviewApplicationName",type:"Byte"},50967:{name:"PreviewApplicationVersion",type:"Byte"},50968:{name:"PreviewSettingsName",type:"Byte"},50969:{name:"PreviewSettingsDigest",type:"Byte"},50970:{name:"PreviewColorSpace",type:"Long"},50971:{name:"PreviewDateTime",type:"Ascii"},50972:{name:"RawImageDigest",type:"Undefined"},50973:{name:"OriginalRawFileDigest",type:"Undefined"},50974:{name:"SubTileBlockSize",type:"Long"},50975:{name:"RowInterleaveFactor",type:"Long"},50981:{name:"ProfileLookTableDims",type:"Long"},50982:{name:"ProfileLookTableData",type:"Float"},51008:{name:"OpcodeList1",type:"Undefined"},51009:{name:"OpcodeList2",type:"Undefined"},51022:{name:"OpcodeList3",type:"Undefined"}},Exif:{33434:{name:"ExposureTime",type:"Rational"},33437:{name:"FNumber",type:"Rational"},34850:{name:"ExposureProgram",type:"Short"},34852:{name:"SpectralSensitivity",type:"Ascii"},34855:{name:"ISOSpeedRatings",type:"Short"},34856:{name:"OECF",type:"Undefined"},34864:{name:"SensitivityType",type:"Short"},34865:{name:"StandardOutputSensitivity",type:"Long"},34866:{name:"RecommendedExposureIndex",type:"Long"},34867:{name:"ISOSpeed",type:"Long"},34868:{name:"ISOSpeedLatitudeyyy",type:"Long"},34869:{name:"ISOSpeedLatitudezzz",type:"Long"},36864:{name:"ExifVersion",type:"Undefined"},36867:{name:"DateTimeOriginal",type:"Ascii"},36868:{name:"DateTimeDigitized",type:"Ascii"},37121:{name:"ComponentsConfiguration",type:"Undefined"},37122:{name:"CompressedBitsPerPixel",type:"Rational"},37377:{name:"ShutterSpeedValue",type:"SRational"},37378:{name:"ApertureValue",type:"Rational"},37379:{name:"BrightnessValue",type:"SRational"},37380:{name:"ExposureBiasValue",type:"SRational"},37381:{name:"MaxApertureValue",type:"Rational"},37382:{name:"SubjectDistance",type:"Rational"},37383:{name:"MeteringMode",type:"Short"},37384:{name:"LightSource",type:"Short"},37385:{name:"Flash",type:"Short"},37386:{name:"FocalLength",type:"Rational"},37396:{name:"SubjectArea",type:"Short"},37500:{name:"MakerNote",type:"Undefined"},37510:{name:"UserComment",type:"Ascii"},37520:{name:"SubSecTime",type:"Ascii"},37521:{name:"SubSecTimeOriginal",type:"Ascii"},37522:{name:"SubSecTimeDigitized",type:"Ascii"},40960:{name:"FlashpixVersion",type:"Undefined"},40961:{name:"ColorSpace",type:"Short"},40962:{name:"PixelXDimension",type:"Long"},40963:{name:"PixelYDimension",type:"Long"},40964:{name:"RelatedSoundFile",type:"Ascii"},40965:{name:"InteroperabilityTag",type:"Long"},41483:{name:"FlashEnergy",type:"Rational"},41484:{name:"SpatialFrequencyResponse",type:"Undefined"},41486:{name:"FocalPlaneXResolution",type:"Rational"},41487:{name:"FocalPlaneYResolution",type:"Rational"},41488:{name:"FocalPlaneResolutionUnit",type:"Short"},41492:{name:"SubjectLocation",type:"Short"},41493:{name:"ExposureIndex",type:"Rational"},41495:{name:"SensingMethod",type:"Short"},41728:{name:"FileSource",type:"Undefined"},41729:{name:"SceneType",type:"Undefined"},41730:{name:"CFAPattern",type:"Undefined"},41985:{name:"CustomRendered",type:"Short"},41986:{name:"ExposureMode",type:"Short"},41987:{name:"WhiteBalance",type:"Short"},41988:{name:"DigitalZoomRatio",type:"Rational"},41989:{name:"FocalLengthIn35mmFilm",type:"Short"},41990:{name:"SceneCaptureType",type:"Short"},41991:{name:"GainControl",type:"Short"},41992:{name:"Contrast",type:"Short"},41993:{name:"Saturation",type:"Short"},41994:{name:"Sharpness",type:"Short"},41995:{name:"DeviceSettingDescription",type:"Undefined"},41996:{name:"SubjectDistanceRange",type:"Short"},42016:{name:"ImageUniqueID",type:"Ascii"},42032:{name:"CameraOwnerName",type:"Ascii"},42033:{name:"BodySerialNumber",type:"Ascii"},42034:{name:"LensSpecification",type:"Rational"},42035:{name:"LensMake",type:"Ascii"},42036:{name:"LensModel",type:"Ascii"},42037:{name:"LensSerialNumber",type:"Ascii"},42240:{name:"Gamma",type:"Rational"}},GPS:{0:{name:"GPSVersionID",type:"Byte"},1:{name:"GPSLatitudeRef",type:"Ascii"},2:{name:"GPSLatitude",type:"Rational"},3:{name:"GPSLongitudeRef",type:"Ascii"},4:{name:"GPSLongitude",type:"Rational"},5:{name:"GPSAltitudeRef",type:"Byte"},6:{name:"GPSAltitude",type:"Rational"},7:{name:"GPSTimeStamp",type:"Rational"},8:{name:"GPSSatellites",type:"Ascii"},9:{name:"GPSStatus",type:"Ascii"},10:{name:"GPSMeasureMode",type:"Ascii"},11:{name:"GPSDOP",type:"Rational"},12:{name:"GPSSpeedRef",type:"Ascii"},13:{name:"GPSSpeed",type:"Rational"},14:{name:"GPSTrackRef",type:"Ascii"},15:{name:"GPSTrack",type:"Rational"},16:{name:"GPSImgDirectionRef",type:"Ascii"},17:{name:"GPSImgDirection",type:"Rational"},18:{name:"GPSMapDatum",type:"Ascii"},19:{name:"GPSDestLatitudeRef",type:"Ascii"},20:{name:"GPSDestLatitude",type:"Rational"},21:{name:"GPSDestLongitudeRef",type:"Ascii"},22:{name:"GPSDestLongitude",type:"Rational"},23:{name:"GPSDestBearingRef",type:"Ascii"},24:{name:"GPSDestBearing",type:"Rational"},25:{name:"GPSDestDistanceRef",type:"Ascii"},26:{name:"GPSDestDistance",type:"Rational"},27:{name:"GPSProcessingMethod",type:"Undefined"},28:{name:"GPSAreaInformation",type:"Undefined"},29:{name:"GPSDateStamp",type:"Ascii"},30:{name:"GPSDifferential",type:"Short"},31:{name:"GPSHPositioningError",type:"Rational"}},Interop:{1:{name:"InteroperabilityIndex",type:"Ascii"}}};g["0th"]=g.Image,g["1st"]=g.Image,n.TAGS=g,n.ImageIFD={ProcessingSoftware:11,NewSubfileType:254,SubfileType:255,ImageWidth:256,ImageLength:257,BitsPerSample:258,Compression:259,PhotometricInterpretation:262,Threshholding:263,CellWidth:264,CellLength:265,FillOrder:266,DocumentName:269,ImageDescription:270,Make:271,Model:272,StripOffsets:273,Orientation:274,SamplesPerPixel:277,RowsPerStrip:278,StripByteCounts:279,XResolution:282,YResolution:283,PlanarConfiguration:284,GrayResponseUnit:290,GrayResponseCurve:291,T4Options:292,T6Options:293,ResolutionUnit:296,TransferFunction:301,Software:305,DateTime:306,Artist:315,HostComputer:316,Predictor:317,WhitePoint:318,PrimaryChromaticities:319,ColorMap:320,HalftoneHints:321,TileWidth:322,TileLength:323,TileOffsets:324,TileByteCounts:325,SubIFDs:330,InkSet:332,InkNames:333,NumberOfInks:334,DotRange:336,TargetPrinter:337,ExtraSamples:338,SampleFormat:339,SMinSampleValue:340,SMaxSampleValue:341,TransferRange:342,ClipPath:343,XClipPathUnits:344,YClipPathUnits:345,Indexed:346,JPEGTables:347,OPIProxy:351,JPEGProc:512,JPEGInterchangeFormat:513,JPEGInterchangeFormatLength:514,JPEGRestartInterval:515,JPEGLosslessPredictors:517,JPEGPointTransforms:518,JPEGQTables:519,JPEGDCTables:520,JPEGACTables:521,YCbCrCoefficients:529,YCbCrSubSampling:530,YCbCrPositioning:531,ReferenceBlackWhite:532,XMLPacket:700,Rating:18246,RatingPercent:18249,ImageID:32781,CFARepeatPatternDim:33421,CFAPattern:33422,BatteryLevel:33423,Copyright:33432,ExposureTime:33434,ImageResources:34377,ExifTag:34665,InterColorProfile:34675,GPSTag:34853,Interlace:34857,TimeZoneOffset:34858,SelfTimerMode:34859,FlashEnergy:37387,SpatialFrequencyResponse:37388,Noise:37389,FocalPlaneXResolution:37390,FocalPlaneYResolution:37391,FocalPlaneResolutionUnit:37392,ImageNumber:37393,SecurityClassification:37394,ImageHistory:37395,ExposureIndex:37397,TIFFEPStandardID:37398,SensingMethod:37399,XPTitle:40091,XPComment:40092,XPAuthor:40093,XPKeywords:40094,XPSubject:40095,PrintImageMatching:50341,DNGVersion:50706,DNGBackwardVersion:50707,UniqueCameraModel:50708,LocalizedCameraModel:50709,CFAPlaneColor:50710,CFALayout:50711,LinearizationTable:50712,BlackLevelRepeatDim:50713,BlackLevel:50714,BlackLevelDeltaH:50715,BlackLevelDeltaV:50716,WhiteLevel:50717,DefaultScale:50718,DefaultCropOrigin:50719,DefaultCropSize:50720,ColorMatrix1:50721,ColorMatrix2:50722,CameraCalibration1:50723,CameraCalibration2:50724,ReductionMatrix1:50725,ReductionMatrix2:50726,AnalogBalance:50727,AsShotNeutral:50728,AsShotWhiteXY:50729,BaselineExposure:50730,BaselineNoise:50731,BaselineSharpness:50732,BayerGreenSplit:50733,LinearResponseLimit:50734,CameraSerialNumber:50735,LensInfo:50736,ChromaBlurRadius:50737,AntiAliasStrength:50738,ShadowScale:50739,DNGPrivateData:50740,MakerNoteSafety:50741,CalibrationIlluminant1:50778,CalibrationIlluminant2:50779,BestQualityScale:50780,RawDataUniqueID:50781,OriginalRawFileName:50827,OriginalRawFileData:50828,ActiveArea:50829,MaskedAreas:50830,AsShotICCProfile:50831,AsShotPreProfileMatrix:50832,CurrentICCProfile:50833,CurrentPreProfileMatrix:50834,ColorimetricReference:50879,CameraCalibrationSignature:50931,ProfileCalibrationSignature:50932,AsShotProfileName:50934,NoiseReductionApplied:50935,ProfileName:50936,ProfileHueSatMapDims:50937,ProfileHueSatMapData1:50938,ProfileHueSatMapData2:50939,ProfileToneCurve:50940,ProfileEmbedPolicy:50941,ProfileCopyright:50942,ForwardMatrix1:50964,ForwardMatrix2:50965,PreviewApplicationName:50966,PreviewApplicationVersion:50967,PreviewSettingsName:50968,PreviewSettingsDigest:50969,PreviewColorSpace:50970,PreviewDateTime:50971,RawImageDigest:50972,OriginalRawFileDigest:50973,SubTileBlockSize:50974,RowInterleaveFactor:50975,ProfileLookTableDims:50981,ProfileLookTableData:50982,OpcodeList1:51008,OpcodeList2:51009,OpcodeList3:51022,NoiseProfile:51041},n.ExifIFD={ExposureTime:33434,FNumber:33437,ExposureProgram:34850,SpectralSensitivity:34852,ISOSpeedRatings:34855,OECF:34856,SensitivityType:34864,StandardOutputSensitivity:34865,RecommendedExposureIndex:34866,ISOSpeed:34867,ISOSpeedLatitudeyyy:34868,ISOSpeedLatitudezzz:34869,ExifVersion:36864,DateTimeOriginal:36867,DateTimeDigitized:36868,ComponentsConfiguration:37121,CompressedBitsPerPixel:37122,ShutterSpeedValue:37377,ApertureValue:37378,BrightnessValue:37379,ExposureBiasValue:37380,MaxApertureValue:37381,SubjectDistance:37382,MeteringMode:37383,LightSource:37384,Flash:37385,FocalLength:37386,SubjectArea:37396,MakerNote:37500,UserComment:37510,SubSecTime:37520,SubSecTimeOriginal:37521,SubSecTimeDigitized:37522,FlashpixVersion:40960,ColorSpace:40961,PixelXDimension:40962,PixelYDimension:40963,RelatedSoundFile:40964,InteroperabilityTag:40965,FlashEnergy:41483,SpatialFrequencyResponse:41484,FocalPlaneXResolution:41486,FocalPlaneYResolution:41487,FocalPlaneResolutionUnit:41488,SubjectLocation:41492,ExposureIndex:41493,SensingMethod:41495,FileSource:41728,SceneType:41729,CFAPattern:41730,CustomRendered:41985,ExposureMode:41986,WhiteBalance:41987,DigitalZoomRatio:41988,FocalLengthIn35mmFilm:41989,SceneCaptureType:41990,GainControl:41991,Contrast:41992,Saturation:41993,Sharpness:41994,DeviceSettingDescription:41995,SubjectDistanceRange:41996,ImageUniqueID:42016,CameraOwnerName:42032,BodySerialNumber:42033,LensSpecification:42034,LensMake:42035,LensModel:42036,LensSerialNumber:42037,Gamma:42240},n.GPSIFD={GPSVersionID:0,GPSLatitudeRef:1,GPSLatitude:2,GPSLongitudeRef:3,GPSLongitude:4,GPSAltitudeRef:5,GPSAltitude:6,GPSTimeStamp:7,GPSSatellites:8,GPSStatus:9,GPSMeasureMode:10,GPSDOP:11,GPSSpeedRef:12,GPSSpeed:13,GPSTrackRef:14,GPSTrack:15,GPSImgDirectionRef:16,GPSImgDirection:17,GPSMapDatum:18,GPSDestLatitudeRef:19,GPSDestLatitude:20,GPSDestLongitudeRef:21,GPSDestLongitude:22,GPSDestBearingRef:23,GPSDestBearing:24,GPSDestDistanceRef:25,GPSDestDistance:26,GPSProcessingMethod:27,GPSAreaInformation:28,GPSDateStamp:29,GPSDifferential:30,GPSHPositioningError:31},n.InteropIFD={InteroperabilityIndex:1},n.GPSHelper={degToDmsRational:function(e){var t=Math.abs(e),n=t%1*60,r=n%1*60;return[[Math.floor(t),1],[Math.floor(n),1],[Math.round(100*r),100]]},dmsRationalToDeg:function(e,t){var n="S"===t||"W"===t?-1:1;return(e[0][0]/e[0][1]+e[1][0]/e[1][1]/60+e[2][0]/e[2][1]/3600)*n}},e.exports&&(t=e.exports=n),t.piexif=n}()}));const Iq=async(e,t,n)=>{const r=await(e=>new Promise((t,n)=>{const r=new FileReader;r.onloadend=()=>t(r.result),r.readAsDataURL(e)}))(e),a=Sq.load(r),s=(await navigator.mediaDevices.enumerateDevices()).filter(e=>"videoinput"===e.kind).map(e=>e.label),i={width:n.width,height:n.height,usedCamera:t.label,camerasOnDevice:s},o={"0th":Object.assign(Object.assign({},a["0th"]),{[Sq.ImageIFD.Model]:i.usedCamera,[Sq.ImageIFD.ImageWidth]:i.width,[Sq.ImageIFD.ImageLength]:i.height}),Exif:Object.assign(Object.assign({},a.Exif),{[Sq.ExifIFD.UserComment]:JSON.stringify(i)}),GPS:Object.assign({},a.GPS),Interop:Object.assign({},a.Interop),"1st":Object.assign({},a["1st"]),thumbnail:a.thumbnail},u=Sq.dump(o),l=Sq.insert(u,r);return await fetch(l).then(e=>e.blob())},Aq=new Image;var Eq;Aq.src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjIyNC45OTk5OTk5OTk5OTk5NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHZlcnNpb249IjEuMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPGcgc3Ryb2tlPSJudWxsIiBpZD0iTGF5ZXIgMSI+CiAgIDxwYXRoIHN0cm9rZT0iIzRjYTU4NSIgaWQ9InN2Z18xIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBmaWxsPSJub25lIiBkPSJtNzQuMjc3NjUsNi45Mjc2MWMtMTEuMzc1OTcsLTAuMDE3MTMgLTMzLjU2NTUxLDUuMTA0MzMgLTQ2LjgxMzE2LDE5LjQ5NDgxYy02Ljc0MTQzLDcuMzIyOTIgLTE4LjEyMjY5LDIzLjA2OTY3IC0xOS4yNjc1OCw1OS42MTM2OWMtMC41MTkwNiwxNi41NjkyMSA1LjA0NTI0LDYwLjYyNTMzIDEwLjI0MDA2LDc2LjQ2Nzc1YzMuNjMxMywxMS4wNzQ2OCAyNy40ODIxNSw0My45MzM0OSA0NC40OTA2LDUzLjY4MjUxYzQuODA3OTEsMi43NTU0NiAxMS4yOTY2OCwyLjY4MjUxIDEyLjQyMjU1LDIuNjgyNTFjMS4xODg3NiwtMC4wODQ1NyA3LjMzMDI2LDAuMDcyOTQgMTIuMTM3NjUsLTIuNjgyNTFjMTcuMDA4NDYsLTkuNzQ5MDIgNDAuNDAyMDgsLTQyLjc2ODUxIDQ0LjQ5MDYsLTUzLjY4MjUxYzQuNDAwMzgsLTExLjc0NDkxIDEwLjc1OTY1LC01OS44OTg1NCAxMC4yNDAwNiwtNzYuNDY3NzVjLTEuMTQ0ODksLTM2LjU0NDAyIC0xMi41MjYxNSwtNTIuMjkwNzcgLTE5LjI2NzU4LC01OS42MTM2OWMtMTMuMjQ3NjUsLTE0LjM5MDQ4IC0zNS4zMDY2MywtMTkuNTI5MzMgLTQ2Ljc3ODI3LC0xOS40OTQ4MWMtMC43NDY4OCwwLjAwMjIyIC0xLjg5NDk0LDAgLTEuODk0OTQsMHoiIHN0cm9rZS13aWR0aD0iNy42NSIvPgogIDwvZz4KIDwvZz4KPC9zdmc+Cg==",function(e){e.JPEG="image/jpeg",e.PNG="image/png"}(Eq||(Eq={}));class Nq{constructor(e,t){this.showMask=!1,this.videoSize={width:0,height:0},this.streamPaused=!1,this.pauseStream=()=>{this.streamPaused=!0,this.videoElement.pause(),this.dropMask(),this.faceDetection&&kq.getInstance().stopDetector()},this.device=e,this.detector=kq.getInstance(this,e.isMobile,t)}setShowMask(e){this.showMask=e}setFaceDetection(e){this.faceDetection=e}setProbabilityThreshold(e){kq.getInstance().setProbabilityThreshold(e)}setCallbackErrors(e){this.callbackErrors=e}setCallbackAutoCapturing(e){this.callbackAutoCapturing=e}setCallbackFaceDetectionErrors(e){this.callbackFaceDetectionErrors=e}static getInstance(e,t){return Nq.instance||(Nq.instance=new Nq(e,t)),Nq.instance}returnErrors(e){this.callbackFaceDetectionErrors(e)}autoCapturing(){this.callbackAutoCapturing()}updateHtmlElements(e,t){this.videoElement=e,this.canvasElement=t,this.detector.updateHtmlElements(e)}async startDetection(){return this.detector.startDetector()}static orientationChange(){Nq.instance&&Nq.getInstance().drawMask()}startStream(e){this.stream&&this.stream.getTracks().forEach(e=>e.stop()),this.stream=e,"srcObject"in this.videoElement?this.videoElement.srcObject=e:this.videoElement.src=window.URL.createObjectURL(e),this.videoElement.play().then(()=>{this.streamPaused=!1,l.cameraReadyEvent(),this.drawMask(),this.faceDetection&&this.startDetection()})}async initStream(e){this.startStream(e)}async resumeStream(){this.streamPaused=!1,await this.videoElement.play(),this.drawMask(),this.faceDetection&&await kq.getInstance().startDetector()}updateCanvasSize(e){this.videoSize={width:this.videoElement.videoWidth,height:this.videoElement.videoHeight},e.width=this.videoSize.width,e.height=this.videoSize.height}dropStream(){this.streamStopped()||(this.stream.getTracks().forEach(e=>e.stop()),this.videoElement.srcObject=null),this.faceDetection&&kq.getInstance().stopDetector()}streamStopped(){return!(this.stream&&this.stream.getTracks&&this.stream.getTracks().length>0)}drawMask(){this.showMask&&!this.streamPaused&&setTimeout(()=>{this.updateCanvasSize(this.canvasElement);const e=this.canvasElement,t=e.getContext("2d"),n=e.width/Aq.width,r=e.height/Aq.height,a=Math.min(n,r),s=e.width{const t=document.createElement("canvas");t.width=this.videoElement.videoWidth,t.height=this.videoElement.videoHeight,e([await this.getFrame(t)])})}getFrame(e){return new Promise(t=>{e.getContext("2d").drawImage(this.videoElement,0,0,e.width,e.height),e.toBlob(e=>{if(e.type!==Eq.JPEG||this.device.isIos)t(e);else try{Iq(e,this.stream.getTracks()[0],this.videoSize).then(e=>t(e))}catch(n){t(e),this.callbackErrors(n,!1)}},Eq.PNG,1)})}}window.addEventListener("resize",Nq.orientationChange,!1),window.addEventListener("orientationchange",Nq.orientationChange,!1);let Cq=class{constructor(e){Object(u.f)(this,e),this.eventVideoStarted=Object(u.b)(this,"videoStarted",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.errorCameraEvent=Object(u.b)(this,"errorCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.callbackErrors=(e,t)=>{t?(this.errorCameraEvent.emit(e),this.eventCloseCamera.emit()):this.errorCameraEvent.emit(e)},this.callbackAutoCapturing=()=>{this.device.isMobile?this.eventMakePhoto.emit():this.eventTakePhoto.emit()},this.callbackFaceDetectionErrors=e=>{l.detectionError(e)}}componentDidLoad(){this.startStream()}render(){const e="camera "+(this.device.isMobile?"cameraMobile":"");return Object(u.d)("div",{class:e},Object(u.d)("video",{loop:!0,autoplay:!0,playsinline:!0,muted:!0,class:"cameraVideo",ref:e=>this.cameraVideo=e}),Object(u.d)("canvas",{class:"cameraCanvas",ref:e=>this.cameraCanvas=e}))}startStream(){Nq.instance||Nq.getInstance(this.device,this.modelPath);const e=Nq.getInstance();e.updateHtmlElements(this.cameraVideo,this.cameraCanvas),e.setShowMask(this.showMask),e.setFaceDetection(this.faceDetection),e.setProbabilityThreshold(this.probabilityThreshold),e.setCallbackErrors(this.callbackErrors),e.setCallbackAutoCapturing(this.callbackAutoCapturing),e.setCallbackFaceDetectionErrors(this.callbackFaceDetectionErrors)}};Cq.style=".camera{width:100%;height:100%;color:white;display:flex;align-items:center;justify-content:center;position:relative}.cameraCanvas{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);max-width:100%;max-height:100%;z-index:2}.cameraVideo{transform:scale(-1, 1);-webkit-transform:scale(-1, 1);z-index:1;position:absolute;max-width:100%;max-height:100%}.cameraMobile{position:fixed;top:0;left:0;background:black}.canvas-on-video{max-width:100%;max-height:100%;position:absolute;left:50%;top:50%;z-index:2;transform:scale(-1, 1)}";let Tq=class{constructor(e){Object(u.f)(this,e),this.updateState=()=>{this._showMask="true"===this.show_mask,this._disable_control_panel="true"===this.disable_control_panel,this._face_detection="true"===this.face_detection,this._stopAfterCapturing="true"===this.stop_after_capturing,this._probabilityThreshold=this.probability_threshold?+this.probability_threshold:50,this.url_logo=this.url_logo?this.url_logo:"data:image/png;charset=utf-8;base64,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",this._debug="true"===this.debug,kq.debug=this._debug},this.photoIsReady=e=>{this._stopAfterCapturing&&this.closeCamera(),l.captureEvent(e)},this.enableButton=()=>{this._resolutionOnPhoto=!0},this.updateState(),this._cameraStatus=0,this._resolutionOnPhoto=!1,this._device=xq(),this._mobile=this._device.isMobile,this._mobileMakePhoto=!1}videoStarted(){this._resolutionOnPhoto=!0}async retakePhoto(){this._mobileMakePhoto=!1,await Nq.getInstance().resumeStream()}takePhoto(){Nq.getInstance().takePhoto().then(e=>{this.photoIsReady(e)})}async openCamera(){this._cameraStatus=1;const e=this._device.isMac?{audio:!1,video:{facingMode:"user",width:1920,height:1080}}:{audio:!1,video:{facingMode:"user",width:{ideal:1920},height:{ideal:1080}}};setTimeout(()=>{navigator.mediaDevices.getUserMedia(e).then(e=>{Nq.getInstance().initStream(e),this.videoStarted()}).catch(e=>{this.closeCamera(),l.errorEvent(e)})},100)}async loadModels(e){await kq.initDetector(e.detail.path)}errorCamera(e){l.errorEvent(e.detail.message)}closeCamera(){Nq.instance&&(this._cameraStatus=0,l.closeEvent(),Nq.getInstance().dropStream(),this._mobileMakePhoto=!1,this._resolutionOnPhoto=!1)}makePhoto(){this._mobile?(this._mobileMakePhoto=!0,Nq.getInstance().pauseStream()):this.takePhoto()}componentWillLoad(){l.init(this.component),navigator.mediaDevices||l.errorEvent("This browser does not support webRTC")}componentDidUpdate(){this.updateState()}render(){let e;return e=this._cameraStatus?Object(u.d)("camera-comp",{class:"block",showMask:this._showMask,device:this._device,faceDetection:this._face_detection,modelPath:this.model_path,probabilityThreshold:this._probabilityThreshold}):Object(u.d)("img",{src:this.url_logo,class:"logo",style:this.logo_style?JSON.parse(this.logo_style):"",alt:"logo"}),Object(u.d)("div",{class:"cameraContainer",id:"cameraContainer",style:{backgroundColor:this.background_color}},Object(u.d)("div",{class:"wrapperCamera",style:{height:this._disable_control_panel?"100%":"65%"}},e),Object(u.d)("control-panel",{class:"block",mobile:this._mobile,disableControlPanel:this._disable_control_panel,cameraStatus:this._cameraStatus,resolutionOnPhoto:this._resolutionOnPhoto,mobileMakePhoto:this._mobileMakePhoto,faceDetection:this._face_detection}))}get component(){return Object(u.c)(this)}};Tq.style=".cameraContainer{width:100%;height:100%;z-index:10;position:relative;overflow:hidden}.logo{max-height:450px;max-width:450px}.wrapperCamera{display:flex;justify-content:center;align-items:center}.block{width:100%;height:100%}@media screen and (orientation: portrait){.history{width:100vw;font-size:20px}@media screen and (max-height: 667px){.logo{background-size:120px;max-height:120px;max-width:120px}}@media screen and (min-height: 668px) and (max-height: 812px){.logo{background-size:140px;max-height:140px;max-width:140px}}@media (max-height: 667px){.logo{margin:0 auto}}}@media screen and (max-height: 414px){.logo{background-size:140px;max-height:140px;max-width:140px}}";const Rq=(e,t)=>[...t];let _q=class{constructor(e){Object(u.f)(this,e),this.eventOpenCamera=Object(u.b)(this,"openCamera",7),this.eventCloseCamera=Object(u.b)(this,"closeCamera",7),this.eventMakePhoto=Object(u.b)(this,"makePhoto",7),this.eventRetakePhoto=Object(u.b)(this,"retakePhoto",7),this.eventTakePhoto=Object(u.b)(this,"takePhoto",7),this.makePhoto=()=>{this.eventMakePhoto.emit()},this.closeCamera=()=>{this.eventCloseCamera.emit()},this.openCamera=()=>{this.eventOpenCamera.emit()},this.takePhoto=()=>{this.eventTakePhoto.emit()},this.retakePhoto=async()=>{this.eventRetakePhoto.emit()}}render(){return Object(u.d)("div",{class:"controlPanel"+(this.mobile?" controlMobile":"")},this.mobile?Object(u.d)("div",null,this.cameraStatus?Object(u.d)("div",null,this.mobileMakePhoto?Object(u.d)("div",null,Object(u.d)("div",{onClick:this.retakePhoto,class:"retake"},"retake"),Object(u.d)("img",{onClick:this.takePhoto,alt:"use this photo",class:"shoot takePhoto",src:"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMjEuMC4yLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDggNDg7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iOTZweCIgaGVpZ2h0PSI5NnB4Ij4KPHBhdGggc3R5bGU9ImZpbGw6I0M4RTZDOTsiIGQ9Ik00NCwyNGMwLDExLjA0NS04Ljk1NSwyMC0yMCwyMFM0LDM1LjA0NSw0LDI0UzEyLjk1NSw0LDI0LDRTNDQsMTIuOTU1LDQ0LDI0eiIvPgo8cGF0aCBzdHlsZT0iZmlsbDojNENBRjUwOyIgZD0iTTM0LjU4NiwxNC41ODZsLTEzLjU3LDEzLjU4NmwtNS42MDItNS41ODZsLTIuODI4LDIuODI4bDguNDM0LDguNDE0bDE2LjM5NS0xNi40MTRMMzQuNTg2LDE0LjU4NnoiLz4KPC9zdmc+Cg=="})):Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto,class:"shoot"}),Object(u.d)("div",{onClick:this.closeCamera,class:"close"},"close")):Object(u.d)("div",null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)("button",{onClick:this.openCamera},"Turn on camera"))):Object(u.d)(Rq,null,this.disableControlPanel?Object(u.d)("div",null):Object(u.d)(Rq,null,this.cameraStatus?Object(u.d)(Rq,null,Object(u.d)("button",{onClick:this.makePhoto,disabled:!this.resolutionOnPhoto},"Capture"),Object(u.d)("button",{onClick:this.closeCamera,class:"cameraOff"},"Close camera")):Object(u.d)("button",{onClick:this.openCamera},"Open camera"))))}};_q.style='.controlPanel{height:35%;display:flex;justify-content:space-evenly;align-items:center;width:100%;max-width:450px;margin:auto}.buttons{width:100%;max-width:450px;display:flex;justify-content:space-evenly;align-items:center}button{width:164px;height:50px;border:none;margin-bottom:10px;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;color:#fff;font-family:"Avenir", Helvetica, sans-serif;font-weight:600;font-size:16px;background-color:#4ca585;outline:none;cursor:pointer}button[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.cameraOff{background-color:#667a87}.cameraOff:hover{background-color:#92a8b5}.shoot{width:50px;height:50px;border-radius:25px;border:2px solid white;outline:none;background-color:red;position:fixed;left:calc(50% - 25px);bottom:10px}.shoot[disabled]{background-color:#aaa;cursor:not-allowed;pointer-events:none}.close{position:fixed;right:6vw;top:2vh;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.retake{position:fixed;right:6vw;bottom:35px;text-shadow:0 0 4px black;color:white;font-size:20px;user-select:none}.takePhoto{width:46px;height:46px;bottom:20px;background:none}@media screen and (orientation:landscape) and (min-width: 360px){.shoot{bottom:calc(50% - 25px);left:auto;right:5vw}}'}.call(this,"/index.js",n(77),"/",n(36),n(241).Buffer,n(245).setImmediate)},function(e,t,n){"use strict";(function(e){ /*! * The buffer module from node.js, for the browser. * diff --git a/spec/components/login_button_component_spec.rb b/spec/components/login_button_component_spec.rb index 27f7c1c8aec..8fc417b3655 100644 --- a/spec/components/login_button_component_spec.rb +++ b/spec/components/login_button_component_spec.rb @@ -11,7 +11,9 @@ end it 'renders button text' do - expect(rendered).to have_text('Sign in with Login.gov') + rendered + element = page.find_css('.login-button').first + expect(element.text.squish).to have_text('Sign in with Login.gov') end it 'renders with design system classes and default color' do diff --git a/spec/components/previews/login_button_component_preview.rb b/spec/components/previews/login_button_component_preview.rb index ff36acdc8cd..9d26ca292a3 100644 --- a/spec/components/previews/login_button_component_preview.rb +++ b/spec/components/previews/login_button_component_preview.rb @@ -1,10 +1,12 @@ class LoginButtonComponentPreview < ButtonComponentPreview # @!group Preview + # @after_render :inject_style def default render(LoginButtonComponent.new) end - # @!endgroup + + # @after_render :inject_style # @param big toggle "Change button size" # @param color select [primary,primary-darker,primary-lighter] "Select button color" def workbench( @@ -18,4 +20,24 @@ def workbench( ), ) end + + private + + def css_file_path + Rails.root.join( + 'app', + 'assets', + 'builds', + 'login_button_component.css', + ) + end + + def inject_style(html) + <<~HTML + + #{html} + HTML + end end diff --git a/spec/controllers/idv/address_controller_spec.rb b/spec/controllers/idv/address_controller_spec.rb index 1f4f2025213..2e908237adc 100644 --- a/spec/controllers/idv/address_controller_spec.rb +++ b/spec/controllers/idv/address_controller_spec.rb @@ -81,6 +81,22 @@ ) end + it 'adds updated_user_data to idv_session' do + expect do + put :update, params: params + end.to change { subject.idv_session.updated_user_address } + + expect(subject.idv_session.updated_user_address).to eql( + Pii::Address.new( + address1: '1234 Main St', + address2: 'Apt B', + city: 'Beverly Hills', + state: 'CA', + zipcode: '90210', + ), + ) + end + it 'invalidates future steps' do expect(subject).to receive(:clear_future_steps!) @@ -97,5 +113,25 @@ error_details: nil }, ) end + + context 'with invalid params' do + render_views + + it 'renders errors if they occur' do + params[:idv_form][:zipcode] = 'this is invalid' + + put :update, params: params + + expect(response).to render_template(:new) + expect(response.body).to include(t('idv.errors.pattern_mismatch.zipcode')) + end + end + + xit 'has the correct `address_edited` value when submitted twice with the same data' do + put :update, params: params + expect(subject.idv_session.address_edited).to eq(true) + put :update, params: params + expect(subject.idv_session.address_edited).to eq(true) + end end end diff --git a/spec/controllers/openid_connect/authorization_controller_spec.rb b/spec/controllers/openid_connect/authorization_controller_spec.rb index 7099b2809c2..2b2bc966954 100644 --- a/spec/controllers/openid_connect/authorization_controller_spec.rb +++ b/spec/controllers/openid_connect/authorization_controller_spec.rb @@ -477,6 +477,16 @@ end end + context 'biometric comparison was performed in-person' do + it 'redirects to the redirect_uri immediately when pii is unlocked if client-side redirect is disabled' do + user.active_profile.idv_level = :in_person + + action + + expect(response).to redirect_to(/^#{params[:redirect_uri]}/) + end + end + context 'selfie capture not enabled, biometric_comparison_check requested by sp' do let(:selfie_capture_enabled) { false } it 'returns status not_acceptable' do diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 3f44b292a67..ac763552800 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -658,7 +658,7 @@ def name_id_version(format_urn) end end - context 'the user has proofed with a biometric check' do + context 'the user has proofed with a biometric check remotely' do before do user.active_profile.update!(idv_level: :unsupervised_with_selfie) end @@ -670,6 +670,18 @@ def name_id_version(format_urn) end end + context 'the user has proofed with a biometric check in-person' do + before do + user.active_profile.update!(idv_level: :in_person) + end + + it 'does not redirect to proofing' do + saml_get_auth(vtr_settings) + expect(response).to redirect_to(sign_up_completed_url) + expect(controller.session[:sp][:vtr]).to eq(['C1.C2.P1.Pb']) + end + end + context 'selfie check is disabled for the environment' do let(:doc_auth_selfie_capture_enabled) { false } diff --git a/spec/controllers/sign_up/cancellations_controller_spec.rb b/spec/controllers/sign_up/cancellations_controller_spec.rb index 5deb7e29a0b..96af62cb09b 100644 --- a/spec/controllers/sign_up/cancellations_controller_spec.rb +++ b/spec/controllers/sign_up/cancellations_controller_spec.rb @@ -32,7 +32,7 @@ it 'redirects if no user is present' do delete :destroy - expect(response).to redirect_to(sign_up_email_resend_url) + expect(response).to redirect_to(sign_up_register_url) end it 'redirects if user has completed sign up' do @@ -68,7 +68,7 @@ delete :destroy expect(flash[:error]).to eq t('errors.messages.confirmation_invalid_token') - expect(response).to redirect_to(sign_up_email_resend_url) + expect(response).to redirect_to(sign_up_register_url) end it 'redirects if confirmation_token is expired' do @@ -89,7 +89,7 @@ subject.session[:user_confirmation_token] = confirmation_token delete :destroy - expect(response).to redirect_to(sign_up_email_resend_url) + expect(response).to redirect_to(sign_up_register_url) expect(flash[:error]).to eq t('errors.messages.confirmation_period_expired') end diff --git a/spec/controllers/sign_up/email_confirmations_controller_spec.rb b/spec/controllers/sign_up/email_confirmations_controller_spec.rb index 38206991c33..36bcd7dc276 100644 --- a/spec/controllers/sign_up/email_confirmations_controller_spec.rb +++ b/spec/controllers/sign_up/email_confirmations_controller_spec.rb @@ -33,7 +33,7 @@ get :create, params: { confirmation_token: nil } expect(flash[:error]).to eq t('errors.messages.confirmation_invalid_token') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end it 'tracks blank email confirmation token' do @@ -47,7 +47,7 @@ get :create, params: { confirmation_token: '' } expect(flash[:error]).to eq t('errors.messages.confirmation_invalid_token') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end it 'tracks confirmation token as a single-quoted empty string' do @@ -61,7 +61,7 @@ get :create, params: { confirmation_token: "''" } expect(flash[:error]).to eq t('errors.messages.confirmation_invalid_token') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end it 'tracks confirmation token as a double-quoted empty string' do @@ -75,7 +75,7 @@ get :create, params: { confirmation_token: '""' } expect(flash[:error]).to eq t('errors.messages.confirmation_invalid_token') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end it 'tracks already confirmed token' do @@ -128,7 +128,7 @@ get :create, params: { confirmation_token: 'foo' } expect(flash[:error]).to eq t('errors.messages.confirmation_period_expired') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end it 'tracks blank confirmation_sent_at as expired token' do @@ -159,7 +159,7 @@ get :create, params: { confirmation_token: 'foo' } expect(flash[:error]).to eq t('errors.messages.confirmation_period_expired') - expect(response).to redirect_to sign_up_email_resend_path + expect(response).to redirect_to sign_up_register_url end describe 'sp metadata' do diff --git a/spec/controllers/sign_up/passwords_controller_spec.rb b/spec/controllers/sign_up/passwords_controller_spec.rb index 4dc62ad4ea1..d6d509ecc22 100644 --- a/spec/controllers/sign_up/passwords_controller_spec.rb +++ b/spec/controllers/sign_up/passwords_controller_spec.rb @@ -162,7 +162,7 @@ user.reload expect(user.valid_password?(password)).to eq false expect(user.confirmed?).to eq false - expect(response).to redirect_to(sign_up_email_resend_url) + expect(response).to redirect_to(sign_up_register_url) end end end @@ -181,7 +181,7 @@ ) get :new, params: { confirmation_token: token } - expect(response).to redirect_to(sign_up_email_resend_url) + expect(response).to redirect_to(sign_up_register_url) end end end diff --git a/spec/controllers/users/piv_cac_recommended_controller_spec.rb b/spec/controllers/users/piv_cac_recommended_controller_spec.rb new file mode 100644 index 00000000000..a9bd996aa9f --- /dev/null +++ b/spec/controllers/users/piv_cac_recommended_controller_spec.rb @@ -0,0 +1,106 @@ +require 'rails_helper' + +RSpec.describe Users::PivCacRecommendedController do + describe 'New user' do + let(:user) { create(:user, email: 'example@example.gov') } + before do + stub_sign_in_before_2fa(user) + stub_analytics + controller.user_session[:in_account_creation_flow] = true + end + + context '#show' do + context 'with user without proper email' do + let(:user) { create(:user, email: 'example@example.com') } + + it 'redirects back to sign in path page' do + get :show + expect(response).to redirect_to(account_path) + end + end + end + + it 'logs analytic event' do + get :show + + expect(@analytics).to have_logged_event(:piv_cac_recommended_visited) + end + end + + describe 'Sign in flow' do + let(:user) { create(:user, :with_phone, { email: 'example@example.gov' }) } + before do + stub_analytics + + stub_sign_in(user) + user.reload + end + + context '#show' do + context 'with user without proper email' do + let(:user) { create(:user, :with_phone, { email: 'example@example.com' }) } + + it 'redirects back to account page' do + get :show + expect(response).to redirect_to(account_path) + end + end + end + end + + context '#confirm' do + let(:user) { create(:user, email: 'example@example.gov') } + before do + stub_sign_in_before_2fa(user) + stub_analytics + controller.user_session[:in_account_creation_flow] = true + end + + it 'directs user to piv cac page' do + post :confirm + + expect(response).to redirect_to(setup_piv_cac_path) + end + + it 'sets piv_cac recommended as set' do + post :confirm + + user.reload + expect(user.piv_cac_recommended_dismissed_at).to be_truthy + end + + it 'logs analytics' do + post :confirm + + expect(@analytics).to have_logged_event(:piv_cac_recommended, action: :accepted) + end + end + + context '#skip' do + let(:user) { create(:user, email: 'example@example.gov') } + before do + stub_sign_in_before_2fa(user) + stub_analytics + controller.user_session[:in_account_creation_flow] = true + end + + it 'directs user to after set up page' do + post :skip + + expect(response).to redirect_to(account_path) + end + + it 'sets piv_cac recommended as set' do + post :skip + + user.reload + expect(user.piv_cac_recommended_dismissed_at).to be_truthy + end + + it 'logs analytics' do + post :skip + + expect(@analytics).to have_logged_event(:piv_cac_recommended, action: :skipped) + end + end +end diff --git a/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb b/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb index 7d4fc7a4971..ce9e9021ec1 100644 --- a/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb +++ b/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb @@ -23,16 +23,31 @@ end context 'with user having gov or mil email' do - let(:user) { create(:user, email: 'example@example.gov') } + let(:user) do + create(:user, email: 'example@example.gov', piv_cac_recommended_dismissed_at: Time.zone.now) + end + context 'having already visited the PIV interstitial page' do + it 'tracks the visit in analytics' do + get :index + + expect(@analytics).to have_logged_event( + 'User Registration: 2FA Setup visited', + enabled_mfa_methods_count: 0, + gov_or_mil_email: true, + ) + end + end - it 'tracks the visit in analytics' do - get :index + context 'directed to page without having visited PIV interstitial page' do + let(:user) do + create(:user, email: 'example@example.gov') + end - expect(@analytics).to have_logged_event( - 'User Registration: 2FA Setup visited', - enabled_mfa_methods_count: 0, - gov_or_mil_email: true, - ) + it 'redirects user to piv_recommended_path' do + get :index + + expect(response).to redirect_to(login_piv_cac_recommended_url) + end end end diff --git a/spec/features/accessibility/user_pages_spec.rb b/spec/features/accessibility/user_pages_spec.rb index bd909ec6123..aacdf55a1f6 100644 --- a/spec/features/accessibility/user_pages_spec.rb +++ b/spec/features/accessibility/user_pages_spec.rb @@ -36,7 +36,8 @@ scenario 'invalid confirmation token' do visit sign_up_create_email_confirmation_path(confirmation_token: '123456') - expect(current_path).to eq(sign_up_email_resend_path) + expect(current_path).to eq(sign_up_register_path) + expect(page).to have_content(t('errors.messages.confirmation_invalid_token')) expect_page_to_have_no_accessibility_violations(page) end end diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index f4367d1fcaf..edd53581850 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -9,6 +9,7 @@ let(:fake_analytics) { FakeAnalytics.new } let(:proofing_device_profiling) { :enabled } let(:threatmetrix) { true } + let(:idv_level) { 'in_person' } let(:threatmetrix_response) do { client: nil, errors: {}, @@ -510,21 +511,21 @@ in_person_verification_pending: true, address_verification_method: 'phone', encrypted_profiles_missing: false, - active_profile_idv_level: nil, pending_profile_idv_level: 'legacy_in_person', + active_profile_idv_level: nil, pending_profile_idv_level: idv_level, proofing_components: { document_check: 'usps', source_check: 'aamva', resolution_check: 'lexis_nexis', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass', address_check: 'lexis_nexis_address' } }, 'IdV: personal key acknowledgment toggled' => { checked: true, - active_profile_idv_level: nil, pending_profile_idv_level: 'legacy_in_person', + active_profile_idv_level: nil, pending_profile_idv_level: idv_level, proofing_components: { document_check: 'usps', source_check: 'aamva', resolution_check: 'lexis_nexis', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass', address_check: 'lexis_nexis_address' } }, 'IdV: personal key submitted' => { address_verification_method: 'phone', fraud_review_pending: false, fraud_rejection: false, in_person_verification_pending: true, deactivation_reason: nil, - active_profile_idv_level: nil, pending_profile_idv_level: 'legacy_in_person', + active_profile_idv_level: nil, pending_profile_idv_level: idv_level, proofing_components: { document_check: 'usps', source_check: 'aamva', resolution_check: 'lexis_nexis', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass', address_check: 'lexis_nexis_address' } }, 'IdV: in person ready to verify visited' => { - active_profile_idv_level: nil, pending_profile_idv_level: 'legacy_in_person', + active_profile_idv_level: nil, pending_profile_idv_level: idv_level, proofing_components: { document_check: 'usps', source_check: 'aamva', resolution_check: 'lexis_nexis', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass', address_check: 'lexis_nexis_address' } }, 'IdV: user clicked what to bring link on ready to verify page' => {}, @@ -867,6 +868,8 @@ to receive(:service_provider_homepage_url).and_return(return_sp_url) allow_any_instance_of(Idv::InPerson::ReadyToVerifyPresenter). to receive(:sp_name).and_return(sp_friendly_name) + allow(IdentityConfig.store).to receive(:in_person_proofing_enforce_tmx). + and_return(true) start_idv_from_sp(:saml) sign_in_and_2fa_user(user) @@ -890,6 +893,7 @@ context 'proofing_device_profiling disabled' do let(:proofing_device_profiling) { :disabled } + let(:idv_level) { 'legacy_in_person' } let(:threatmetrix) { false } let(:threatmetrix_response) do { client: 'tmx_disabled', diff --git a/spec/features/idv/doc_auth/document_capture_spec.rb b/spec/features/idv/doc_auth/document_capture_spec.rb index d551098ae4e..84cc9b98e25 100644 --- a/spec/features/idv/doc_auth/document_capture_spec.rb +++ b/spec/features/idv/doc_auth/document_capture_spec.rb @@ -256,7 +256,7 @@ and_return(true) end - context 'on mobile platform' do + context 'on mobile platform', allow_browser_log: true do before do # mock mobile device as cameraCapable, this allows us to process allow_any_instance_of(ActionController::Parameters). @@ -265,41 +265,7 @@ end end - it 'proceeds to the next page with valid info, including a selfie image' do - perform_in_browser(:mobile) do - visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - - expect(page).to have_current_path(idv_document_capture_url) - expect(max_capture_attempts_before_native_camera.to_i). - to eq(ActiveSupport::Duration::SECONDS_PER_HOUR) - expect(max_submission_attempts_before_native_camera.to_i). - to eq(ActiveSupport::Duration::SECONDS_PER_HOUR) - expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id')) - expect_doc_capture_page_header(t('doc_auth.headings.document_capture_with_selfie')) - expect_doc_capture_id_subheader - expect_doc_capture_selfie_subheader - attach_liveness_images - submit_images - - expect(page).to have_current_path(idv_ssn_url) - expect_costing_for_document - expect(DocAuthLog.find_by(user_id: user.id).state).to eq('MT') - - expect(page).to have_current_path(idv_ssn_url) - fill_out_ssn_form_ok - click_idv_continue - complete_verify_step - expect(page).to have_current_path(idv_phone_url) - end - end - context 'when a selfie is required by SP', allow_browser_log: true do - before do - allow_any_instance_of(FederatedProtocols::Oidc). - to receive(:biometric_comparison_required?). - and_return(true) - end + context 'with a passing selfie' do it 'proceeds to the next page with valid info, including a selfie image' do perform_in_browser(:mobile) do visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) @@ -307,6 +273,10 @@ complete_doc_auth_steps_before_document_capture_step expect(page).to have_current_path(idv_document_capture_url) + expect(max_capture_attempts_before_native_camera.to_i). + to eq(ActiveSupport::Duration::SECONDS_PER_HOUR) + expect(max_submission_attempts_before_native_camera.to_i). + to eq(ActiveSupport::Duration::SECONDS_PER_HOUR) expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id')) expect_doc_capture_page_header(t('doc_auth.headings.document_capture_with_selfie')) expect_doc_capture_id_subheader @@ -325,160 +295,160 @@ expect(page).to have_current_path(idv_phone_url) end end - context 'selfie with error is uploaded', - allow_browser_log: true do - it 'try again and page show no liveness inline error message' do - visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - attach_images( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_no_liveness.yml' - ), - ) - attach_selfie( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_no_liveness.yml' - ), - ) - submit_images - message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) - expect(page).to have_content(message) - detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_not_live')) - security_message = strip_tags( - t( - 'idv.warning.attempts_html', - count: IdentityConfig.store.doc_auth_max_attempts - 1, - ), - ) - expect(page).to have_content(detail_message << "\n" << security_message) - review_issues_header = strip_tags( - t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), - ) - expect(page).to have_content(review_issues_header) - expect(page).to have_current_path(idv_document_capture_path) - click_try_again - expect(page).to have_current_path(idv_document_capture_path) - inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) - expect(page).to have_content(inline_error) - end - it 'try again and page show poor quality inline error message' do - visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - attach_images( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_poor_quality.yml' - ), - ) - attach_selfie( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_poor_quality.yml' - ), - ) - submit_images - message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) - expect(page).to have_content(message) - detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_poor_quality')) - security_message = strip_tags( - t( - 'idv.warning.attempts_html', - count: IdentityConfig.store.doc_auth_max_attempts - 1, - ), - ) - expect(page).to have_content(detail_message << "\n" << security_message) - review_issues_header = strip_tags( - t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), - ) - expect(page).to have_content(review_issues_header) - expect(page).to have_current_path(idv_document_capture_path) - click_try_again - expect(page).to have_current_path(idv_document_capture_path) - inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) - expect(page).to have_content(inline_error) - end + end - it 'try again and page show selfie fail inline error message' do - visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - attach_images( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_portrait_match_failure.yml' - ), - ) - attach_selfie( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_portrait_match_failure.yml' - ), - ) - submit_images - message = strip_tags(t('errors.doc_auth.selfie_fail_heading')) - expect(page).to have_content(message) - detail_message = strip_tags(t('doc_auth.errors.general.selfie_failure')) - security_message = strip_tags( - t( - 'idv.warning.attempts_html', - count: IdentityConfig.store.doc_auth_max_attempts - 1, - ), - ) - expect(page).to have_content(detail_message << "\n" << security_message) - review_issues_header = strip_tags( - t('errors.doc_auth.selfie_fail_heading'), - ) - expect(page).to have_content(review_issues_header) - expect(page).to have_current_path(idv_document_capture_path) - click_try_again - expect(page).to have_current_path(idv_document_capture_path) - inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) - expect(page).to have_content(inline_error) - end + context 'selfie with error is uploaded' do + it 'try again and page show no liveness inline error message' do + visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) + sign_in_and_2fa_user(user) + complete_doc_auth_steps_before_document_capture_step + attach_images( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_no_liveness.yml' + ), + ) + attach_selfie( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_no_liveness.yml' + ), + ) + submit_images + message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) + expect(page).to have_content(message) + detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_not_live')) + security_message = strip_tags( + t( + 'idv.warning.attempts_html', + count: IdentityConfig.store.doc_auth_max_attempts - 1, + ), + ) + expect(page).to have_content(detail_message << "\n" << security_message) + review_issues_header = strip_tags( + t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), + ) + expect(page).to have_content(review_issues_header) + expect(page).to have_current_path(idv_document_capture_path) + click_try_again + expect(page).to have_current_path(idv_document_capture_path) + inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) + expect(page).to have_content(inline_error) + end + it 'try again and page show poor quality inline error message' do + visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) + sign_in_and_2fa_user(user) + complete_doc_auth_steps_before_document_capture_step + attach_images( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_poor_quality.yml' + ), + ) + attach_selfie( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_poor_quality.yml' + ), + ) + submit_images + message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) + expect(page).to have_content(message) + detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_poor_quality')) + security_message = strip_tags( + t( + 'idv.warning.attempts_html', + count: IdentityConfig.store.doc_auth_max_attempts - 1, + ), + ) + expect(page).to have_content(detail_message << "\n" << security_message) + review_issues_header = strip_tags( + t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), + ) + expect(page).to have_content(review_issues_header) + expect(page).to have_current_path(idv_document_capture_path) + click_try_again + expect(page).to have_current_path(idv_document_capture_path) + inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) + expect(page).to have_content(inline_error) end - context 'with Attention with Barcode' do - it 'try again and page show selfie fail inline error message' do - visit_idp_from_oidc_sp_with_ial2 - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - attach_images( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_barcode_attention_liveness_fail.yml' - ), - ) - attach_selfie( - Rails.root.join( - 'spec', 'fixtures', - 'ial2_test_credential_barcode_attention_liveness_fail.yml' - ), - ) - submit_images - message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) - expect(page).to have_content(message) - detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_not_live')) - security_message = strip_tags( - t( - 'idv.warning.attempts_html', - count: IdentityConfig.store.doc_auth_max_attempts - 1, - ), - ) - expect(page).to have_content(detail_message << "\n" << security_message) - review_issues_header = strip_tags( - t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), - ) - expect(page).to have_content(review_issues_header) - expect(page).to have_current_path(idv_document_capture_path) - click_try_again - expect(page).to have_current_path(idv_document_capture_path) - inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) - expect(page).to have_content(inline_error) - end + it 'try again and page show selfie fail inline error message' do + visit_idp_from_oidc_sp_with_ial2(biometric_comparison_required: true) + sign_in_and_2fa_user(user) + complete_doc_auth_steps_before_document_capture_step + attach_images( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_portrait_match_failure.yml' + ), + ) + attach_selfie( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_portrait_match_failure.yml' + ), + ) + submit_images + message = strip_tags(t('errors.doc_auth.selfie_fail_heading')) + expect(page).to have_content(message) + detail_message = strip_tags(t('doc_auth.errors.general.selfie_failure')) + security_message = strip_tags( + t( + 'idv.warning.attempts_html', + count: IdentityConfig.store.doc_auth_max_attempts - 1, + ), + ) + expect(page).to have_content(detail_message << "\n" << security_message) + review_issues_header = strip_tags( + t('errors.doc_auth.selfie_fail_heading'), + ) + expect(page).to have_content(review_issues_header) + expect(page).to have_current_path(idv_document_capture_path) + click_try_again + expect(page).to have_current_path(idv_document_capture_path) + inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) + expect(page).to have_content(inline_error) + end + end + context 'with Attention with Barcode' do + it 'try again and page show selfie fail inline error message' do + visit_idp_from_oidc_sp_with_ial2 + sign_in_and_2fa_user(user) + complete_doc_auth_steps_before_document_capture_step + attach_images( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_barcode_attention_liveness_fail.yml' + ), + ) + attach_selfie( + Rails.root.join( + 'spec', 'fixtures', + 'ial2_test_credential_barcode_attention_liveness_fail.yml' + ), + ) + submit_images + message = strip_tags(t('errors.doc_auth.selfie_not_live_or_poor_quality_heading')) + expect(page).to have_content(message) + detail_message = strip_tags(t('doc_auth.errors.alerts.selfie_not_live')) + security_message = strip_tags( + t( + 'idv.warning.attempts_html', + count: IdentityConfig.store.doc_auth_max_attempts - 1, + ), + ) + + expect(page).to have_content(detail_message << "\n" << security_message) + review_issues_header = strip_tags( + t('errors.doc_auth.selfie_not_live_or_poor_quality_heading'), + ) + expect(page).to have_content(review_issues_header) + expect(page).to have_current_path(idv_document_capture_path) + click_try_again + expect(page).to have_current_path(idv_document_capture_path) + inline_error = strip_tags(t('doc_auth.errors.general.selfie_failure')) + expect(page).to have_content(inline_error) end end diff --git a/spec/features/users/sign_in_spec.rb b/spec/features/users/sign_in_spec.rb index c5c8251ecae..f7ff848b63d 100644 --- a/spec/features/users/sign_in_spec.rb +++ b/spec/features/users/sign_in_spec.rb @@ -162,6 +162,30 @@ to(include(expected_form_action)) end + scenario 'User with gov/mil email directed to recommended PIV page' do + user = create(:user, :with_phone, { email: 'example@example.gov' }) + + visit new_user_session_path + fill_in_credentials_and_submit(user.email, user.password) + fill_in_code_with_last_phone_otp + click_submit_default + expect(page).to have_current_path(login_piv_cac_recommended_path) + click_button(t('two_factor_authentication.piv_cac_upsell.add_piv')) + expect(page).to have_current_path(setup_piv_cac_path) + end + + scenario 'User with gov/mil email and skips recommendation page' do + user = create(:user, :with_phone, { email: 'example@example.gov' }) + + visit new_user_session_path + fill_in_credentials_and_submit(user.email, user.password) + fill_in_code_with_last_phone_otp + click_submit_default + expect(page).to have_current_path(login_piv_cac_recommended_path) + click_button(t('two_factor_authentication.piv_cac_upsell.skip')) + expect(page).to have_current_path(account_path) + end + scenario 'user attempts sign in with piv/cac with no account then creates account' do visit_idp_from_sp_with_ial1(:oidc) click_on t('account.login.piv_cac') diff --git a/spec/features/users/sign_up_spec.rb b/spec/features/users/sign_up_spec.rb index 5631fb54df1..5e4c376801b 100644 --- a/spec/features/users/sign_up_spec.rb +++ b/spec/features/users/sign_up_spec.rb @@ -271,7 +271,7 @@ def clipboard_text it 'returns them to the resend email confirmation page' do visit sign_up_enter_password_path(confirmation_token: 'foo', request_id: 'bar') - expect(page).to have_current_path(sign_up_email_resend_path) + expect(page).to have_current_path(sign_up_register_path) expect(page). to have_content t('errors.messages.confirmation_invalid_token') @@ -518,6 +518,34 @@ def clipboard_text end end + describe 'mil or gov email account' do + before do + confirm_email('test@test.gov') + submit_form_with_valid_password + end + it 'should land user on piv cac suggestion page' do + expect(current_path).to eq login_piv_cac_recommended_path + end + + context 'user can skip piv cac prompt' do + it 'should skip piv cac prompt and land on mfa screen' do + expect(current_path).to eq login_piv_cac_recommended_path + click_button t('two_factor_authentication.piv_cac_upsell.choose_other_method') + + expect(current_path).to eq authentication_methods_setup_path + end + end + + context 'user who selects to add piv is directed to piv screen' do + it 'should be directed straight to piv add screen' do + expect(current_path).to eq login_piv_cac_recommended_path + click_button t('two_factor_authentication.piv_cac_upsell.add_piv') + + expect(current_path).to eq setup_piv_cac_path + end + end + end + def click_2fa_option(option) find("label[for='two_factor_options_form_selection_#{option}']").click end diff --git a/spec/features/visitors/email_confirmation_spec.rb b/spec/features/visitors/email_confirmation_spec.rb index e424d34d319..ab984f0a983 100644 --- a/spec/features/visitors/email_confirmation_spec.rb +++ b/spec/features/visitors/email_confirmation_spec.rb @@ -1,6 +1,22 @@ require 'rails_helper' RSpec.feature 'Email confirmation during sign up', allowed_extra_analytics: [:*] do + it 'requires user to accept rules of use when registering email' do + visit sign_up_email_path + fill_in t('forms.registration.labels.email'), with: 'test@example.com' + click_submit_default + + expect(page).to have_current_path(sign_up_email_path) + expect(page).to have_content(t('errors.registration.terms')) + + fill_in t('forms.registration.labels.email'), with: 'test@example.com' + check t('sign_up.terms', app_name: APP_NAME) + click_submit_default + + expect(page).to have_current_path(sign_up_verify_email_url) + expect(page).not_to have_content(t('errors.registration.terms')) + end + scenario 'confirms valid email and sets valid password' do reset_email email = 'test@example.com' diff --git a/spec/features/visitors/password_recovery_spec.rb b/spec/features/visitors/password_recovery_spec.rb index beafe728c4b..efaa5e59b32 100644 --- a/spec/features/visitors/password_recovery_spec.rb +++ b/spec/features/visitors/password_recovery_spec.rb @@ -66,9 +66,10 @@ user = create(:user, :unconfirmed) confirm_last_user reset_email - visit sign_up_email_resend_path + visit sign_up_email_path fill_in t('forms.registration.labels.email'), with: user.email - click_button t('forms.buttons.resend_confirmation') + check t('sign_up.terms', app_name: APP_NAME) + click_submit_default open_last_email click_email_link_matching(/confirmation_token/) end diff --git a/spec/features/visitors/resend_email_confirmation_spec.rb b/spec/features/visitors/resend_email_confirmation_spec.rb index 9864029c032..1f86dc3459e 100644 --- a/spec/features/visitors/resend_email_confirmation_spec.rb +++ b/spec/features/visitors/resend_email_confirmation_spec.rb @@ -1,84 +1,17 @@ require 'rails_helper' -require 'email_spec' -RSpec.feature 'Visit requests confirmation instructions again during sign up', - allowed_extra_analytics: [:*] do - include(EmailSpec::Helpers) - include(EmailSpec::Matchers) - - let!(:user) { build(:user, confirmed_at: nil) } +RSpec.feature 'Visit requests confirmation instructions again during sign up' do + let!(:user) { create(:user, :unconfirmed) } before(:each) do - visit sign_up_email_resend_path + visit sign_up_email_path end scenario 'user can resend their confirmation instructions via email' do - user.save! fill_in t('forms.registration.labels.email'), with: user.email + check t('sign_up.terms', app_name: APP_NAME) + click_submit_default - click_button t('forms.buttons.resend_confirmation') expect(unread_emails_for(user.email)).to be_present end - - scenario 'user rate limited sending confirmation emails' do - user.save! - email = user.email - - max_attempts = IdentityConfig.store.reg_unconfirmed_email_max_attempts - (max_attempts - 1).times do |i| - submit_resend_email_confirmation(email) - expect(unread_emails_for(user.email).size).to eq(i + 1) - end - - expect(unread_emails_for(user.email).size).to eq(max_attempts - 1) - submit_resend_email_confirmation(email) - expect(unread_emails_for(user.email).size).to eq(max_attempts - 1) - end - - scenario 'user enters email with invalid format' do - invalid_addresses = [ - 'user@domain-without-suffix', - 'Buy Medz 0nl!ne http://pharma342.onlinestore.com', - ] - allow(ValidateEmail).to receive(:mx_valid?).and_return(false) - - button = t('forms.buttons.resend_confirmation') - invalid_addresses.each do |email| - fill_in t('forms.registration.labels.email'), with: email - click_button button - button = t('forms.buttons.submit.default') - - expect(page).to have_content t('valid_email.validations.email.invalid') - end - end - - scenario 'user enters email with invalid domain name' do - invalid_addresses = [ - 'foo@bar.com', - 'foo@example.com', - ] - allow(ValidateEmail).to receive(:mx_valid?).and_return(false) - - button = t('forms.buttons.resend_confirmation') - invalid_addresses.each do |email| - fill_in t('forms.registration.labels.email'), with: email - click_button button - button = t('forms.buttons.submit.default') - - expect(page).to have_content t('valid_email.validations.email.invalid') - end - end - - scenario 'user enters empty email' do - fill_in t('forms.registration.labels.email'), with: '' - click_button t('forms.buttons.resend_confirmation') - - expect(page).to have_content t('valid_email.validations.email.invalid') - end - - def submit_resend_email_confirmation(email) - visit sign_up_email_resend_path - fill_in t('forms.registration.labels.email'), with: email - click_button t('forms.buttons.resend_confirmation') - end end diff --git a/spec/forms/idv/address_form_spec.rb b/spec/forms/idv/address_form_spec.rb new file mode 100644 index 00000000000..e8287f6b073 --- /dev/null +++ b/spec/forms/idv/address_form_spec.rb @@ -0,0 +1,78 @@ +require 'rails_helper' + +RSpec.describe Idv::AddressForm do + let(:pii) do + { + first_name: 'Test', + last_name: 'McTesterson', + address1: '123 Main St', + address2: nil, + city: 'Testertown', + state: 'TX', + zipcode: '11111', + } + end + + let(:params) do + { + address1: '456 Other St', + address2: 'Apt 1', + city: 'McTestville', + state: 'IL', + zipcode: '22222', + } + end + + it 'is initialized with values from the hash in the initializer' do + address_form = Idv::AddressForm.new(pii) + expect(address_form.address1).to eq('123 Main St') + expect(address_form.address2).to eq(nil) + expect(address_form.city).to eq('Testertown') + expect(address_form.state).to eq('TX') + expect(address_form.zipcode).to eq('11111') + end + + describe '#submit' do + context 'with valid params' do + it 'returns a successful result' do + result = Idv::AddressForm.new(pii).submit(params) + + expect(result.success?).to eq(true) + expect(result.extra[:address_edited]).to eq(true) + end + end + + context 'with a malformed param' do + it 'returns an error result' do + params[:zipcode] = 'this is not a valid zipcde' + + result = Idv::AddressForm.new(pii).submit(params) + + expect(result.success?).to eq(false) + expect(result.errors[:zipcode]).to be_present + end + end + + context 'with a missing params' do + it 'returns an error result' do + params.delete(:zipcode) + + result = Idv::AddressForm.new(pii).submit(params) + + expect(result.success?).to eq(false) + expect(result.errors[:zipcode]).to be_present + end + end + + context 'the user submits the same address that is in the pii' do + it 'does not set `address_edited` to true' do + params = pii.slice(:address1, :address2, :city, :state, :zipcode) + + result = Idv::AddressForm.new(pii).submit(params) + + expect(result.success?).to eq(true) + expect(result.extra[:address_edited]).to eq(false) + end + end + end +end diff --git a/spec/forms/register_user_email_form_spec.rb b/spec/forms/register_user_email_form_spec.rb index 6bc9992f895..8d1da4e8afd 100644 --- a/spec/forms/register_user_email_form_spec.rb +++ b/spec/forms/register_user_email_form_spec.rb @@ -374,6 +374,37 @@ end end + context 'when terms accepted using castable value' do + it 'is successful' do + result = subject.submit(email: unregistered_email_address, terms_accepted: 'true') + + expect(result.to_h).to eq( + success: true, + errors: {}, + email_already_exists: false, + rate_limited: false, + user_id: User.find_with_email(unregistered_email_address).uuid, + domain_name: email_domain, + ) + end + end + + context 'when terms not accepted' do + it 'is unsuccessful with error for terms accepted' do + result = subject.submit(email: unregistered_email_address) + + expect(result.to_h).to eq( + success: false, + errors: { terms_accepted: [t('errors.registration.terms')] }, + error_details: { terms_accepted: { terms: true } }, + email_already_exists: false, + rate_limited: false, + user_id: 'anonymous-uuid', + domain_name: email_domain, + ) + end + end + context 'when request_id is invalid' do it 'returns successful and does not include request_id in email' do invalid_id = 'fake_id' diff --git a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx index ecd4bce9beb..8f0f2a03605 100644 --- a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx +++ b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx @@ -152,7 +152,7 @@ describe('document-capture/components/documents-step', () => { ], [DocumentsStep], ); - const { getByRole, getByLabelText } = render(); + const { queryByRole, getByRole, getByLabelText } = render(); const front = getByLabelText('doc_auth.headings.document_capture_front'); const back = getByLabelText('doc_auth.headings.document_capture_back'); @@ -160,7 +160,7 @@ describe('document-capture/components/documents-step', () => { name: 'doc_auth.headings.document_capture', level: 1, }); - const idHeader = getByRole('heading', { + const idHeader = queryByRole('heading', { name: 'doc_auth.headings.document_capture_subheader_id', level: 2, }); @@ -168,6 +168,6 @@ describe('document-capture/components/documents-step', () => { expect(front).to.be.ok(); expect(back).to.be.ok(); expect(pageHeader).to.be.ok(); - expect(idHeader).to.be.ok(); + expect(idHeader).to.be.not.ok(); }); }); diff --git a/spec/javascript/packages/document-capture/hooks/use-log-camera-info-spec.tsx b/spec/javascript/packages/document-capture/hooks/use-log-camera-info-spec.tsx new file mode 100644 index 00000000000..cd2a84206d4 --- /dev/null +++ b/spec/javascript/packages/document-capture/hooks/use-log-camera-info-spec.tsx @@ -0,0 +1,107 @@ +import sinon from 'sinon'; +import { render } from '@testing-library/react'; +import { useLogCameraInfo } from '@18f/identity-document-capture/hooks/use-log-camera-info'; +import { AnalyticsContextProvider } from '@18f/identity-document-capture/context/analytics'; +import { useDefineProperty } from '@18f/identity-test-helpers'; +import { waitFor } from '@testing-library/dom'; + +interface MockComponentProps { + isBackOfId: boolean; + hasStartedCropping: boolean; +} + +function MockComponent({ isBackOfId, hasStartedCropping }: MockComponentProps) { + useLogCameraInfo({ isBackOfId, hasStartedCropping }); + return
mockcomponent
; +} + +const mockTrack = { + label: 'mockTrackLabel', + getSettings: () => ({ + frameRate: 60, + height: 3000, + width: 3000, + }), +}; + +const mockDeviceId = 'mockDeviceId'; +const mockGetVideoTracks = () => [mockTrack]; +const mockDevice = { + kind: 'videoinput', + deviceId: mockDeviceId, +}; + +const mockGetUserMediaThrowsError = () => { + throw new Error('camera logging failed'); +}; +const mockGetUserMedia = () => + new Promise((resolve) => resolve({ getVideoTracks: mockGetVideoTracks })); +const mockEnumerateDevices = () => new Promise((resolve) => resolve([mockDevice])); + +describe('document-capture/hooks/use-log-camera-info', () => { + const defineProperty = useDefineProperty(); + beforeEach(() => { + defineProperty(global.navigator, 'mediaDevices', { + value: { + getUserMedia: mockGetUserMedia, + enumerateDevices: mockEnumerateDevices, + }, + configurable: true, + writable: true, + }); + }); + + it('logs camera info when isBackOfId and hasStartedCropping are both true', async () => { + const trackEvent = sinon.stub(); + const [isBackOfId, hasStartedCropping] = [true, true]; + const { findByText } = render( + + + , + ); + + await waitFor(() => findByText('mockcomponent')); + expect(trackEvent).to.have.been.calledWith('idv_camera_info_logged'); + }); + + it('doesnt log camera info when isBackOfId is false', async () => { + const trackEvent = sinon.stub(); + const [isBackOfId, hasStartedCropping] = [false, true]; + const { findByText } = render( + + + , + ); + + await waitFor(() => findByText('mockcomponent')); + expect(trackEvent).not.to.have.been.called(); + }); + + it('doesnt log camera info when hasStartedCropping is false', async () => { + const trackEvent = sinon.stub(); + const [isBackOfId, hasStartedCropping] = [true, false]; + const { findByText } = render( + + + , + ); + + await waitFor(() => findByText('mockcomponent')); + expect(trackEvent).not.to.have.been.called(); + }); + + it('logs a camera info error when getting media info fails', async () => { + const trackEvent = sinon.stub(); + const [isBackOfId, hasStartedCropping] = [true, true]; + // Override a previously mocked window function to always throw an error + global.navigator.mediaDevices.getUserMedia = mockGetUserMediaThrowsError; + const { findByText } = render( + + + , + ); + + await waitFor(() => findByText('mockcomponent')); + expect(trackEvent).to.have.been.calledWith('idv_camera_info_error'); + }); +}); diff --git a/spec/javascript/support/document-capture.jsx b/spec/javascript/support/document-capture.jsx index f547b254396..3cb935da3dc 100644 --- a/spec/javascript/support/document-capture.jsx +++ b/spec/javascript/support/document-capture.jsx @@ -92,6 +92,7 @@ export function useAcuant() { START_FAIL_CODE: 'start-fail-code', REPEAT_FAIL_CODE: 'repeat-fail-code', SEQUENCE_BREAK_CODE: 'sequence-break-code', + setUnexpectedErrorCallback: sinon.stub(), }; // @ts-ignore window.AcuantCamera = { isCameraSupported, triggerCapture }; diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 45bbc1602d6..38abe57012f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1435,6 +1435,12 @@ def it_should_not_send_survey expect(user.identity_verified_with_selfie?).to eq false end + it 'return true if user has an active in-person profile' do + active_profile.idv_level = :in_person + active_profile.save + expect(user.identity_verified_with_selfie?).to eq true + end + context 'user does not have active profile' do let(:active_profile) { nil } it 'returns false' do diff --git a/spec/presenters/piv_cac_recommended_presenter_spec.rb b/spec/presenters/piv_cac_recommended_presenter_spec.rb new file mode 100644 index 00000000000..0044df6adfa --- /dev/null +++ b/spec/presenters/piv_cac_recommended_presenter_spec.rb @@ -0,0 +1,93 @@ +require 'rails_helper' + +RSpec.describe PivCacRecommendedPresenter do + let(:user) { create(:user, email: 'example@example.gov') } + let(:presenter) { described_class.new(user) } + + describe '#info' do + context 'when is a gov email' do + context 'when existing user' do + let(:user) { create(:user, :with_phone, { email: 'example@example.gov' }) } + it 'should match existing user .gov text' do + expect(presenter.info).to eq( + t( + 'two_factor_authentication.piv_cac_upsell.existing_user_info', + email_type: '.gov', + ), + ) + end + end + + context 'when user has no mfa methods' do + let(:user) { create(:user, email: 'example@example.gov') } + it 'should match new user .gov text' do + expect(presenter.info).to eq( + t( + 'two_factor_authentication.piv_cac_upsell.new_user_info', + email_type: '.gov', + ), + ) + end + end + end + + context 'when user has a .mil email' do + context 'when existing user' do + let(:user) { create(:user, :with_phone, { email: 'example@example.mil' }) } + it 'should match existing user .mil text' do + expect(presenter.info).to eq( + t( + 'two_factor_authentication.piv_cac_upsell.existing_user_info', + email_type: '.mil', + ), + ) + end + end + + context 'when user has no mfa methods yet' do + let(:user) { create(:user, email: 'example@example.mil') } + it 'should match new user .mil text' do + expect(presenter.info).to eq( + t( + 'two_factor_authentication.piv_cac_upsell.new_user_info', + email_type: '.mil', + ), + ) + end + end + end + end + + describe '#email_type' do + context 'when is gov email' do + it 'should return .gov' do + expect(presenter.email_type).to eq('.gov') + end + end + + context 'when .mil email' do + let(:user) { create(:user, email: 'example@example.mil') } + it 'should return .mil' do + expect(presenter.email_type).to eq('.mil') + end + end + end + + describe '#skip_text' do + context 'when existing user' do + let(:user) { create(:user, :with_phone, { email: 'example@example.mil' }) } + it 'should return skip text' do + expect(presenter.skip_text).to eq(t('two_factor_authentication.piv_cac_upsell.skip')) + end + end + + context 'when user has no mfa methods yet' do + let(:user) { create(:user, email: 'example@example.mil') } + it 'should return choose another method text' do + expect(presenter.skip_text).to eq( + t('two_factor_authentication.piv_cac_upsell.choose_other_method'), + ) + end + end + end +end diff --git a/spec/services/idv/profile_maker_spec.rb b/spec/services/idv/profile_maker_spec.rb index ff18973a700..89295c9674b 100644 --- a/spec/services/idv/profile_maker_spec.rb +++ b/spec/services/idv/profile_maker_spec.rb @@ -6,6 +6,7 @@ let(:user) { create(:user, :fully_registered) } let(:user_password) { user.password } let(:initiating_service_provider) { nil } + let(:in_person_proofing_enforce_tmx_mock) { false } subject do described_class.new( @@ -135,28 +136,78 @@ end context 'with in_person_verification_needed' do - let(:profile) do - subject.save_profile( - fraud_pending_reason: nil, - gpo_verification_needed: false, - deactivation_reason: nil, - in_person_verification_needed: true, - selfie_check_performed: false, - ) - end - it 'creates a pending profile for in person verification' do - expect(profile.activated_at).to be_nil - expect(profile.active).to eq(false) - expect(profile.deactivation_reason).to be_nil - expect(profile.fraud_pending_reason).to be_nil - expect(profile.in_person_verification_pending?).to eq(true) - expect(profile.fraud_review_pending?).to eq(false) - expect(profile.gpo_verification_pending_at.present?).to eq(false) - expect(profile.initiating_service_provider).to eq(nil) - expect(profile.verified_at).to be_nil + context 'when threatmetrix decisioning is disabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_proofing_enforce_tmx). + and_return(in_person_proofing_enforce_tmx_mock) + allow(IdentityConfig.store).to receive(:proofing_device_profiling). + and_return(:disabled) + end + + let(:profile) do + subject.save_profile( + fraud_pending_reason: nil, + gpo_verification_needed: false, + deactivation_reason: nil, + in_person_verification_needed: true, + selfie_check_performed: false, + ) + end + + it 'creates a pending profile for in person verification' do + expect(profile.activated_at).to be_nil + expect(profile.active).to eq(false) + expect(profile.deactivation_reason).to be_nil + expect(profile.fraud_pending_reason).to be_nil + expect(profile.in_person_verification_pending?).to eq(true) + expect(profile.fraud_review_pending?).to eq(false) + expect(profile.gpo_verification_pending_at.present?).to eq(false) + expect(profile.initiating_service_provider).to eq(nil) + expect(profile.verified_at).to be_nil + end + + it 'marks the profile as legacy_in_person' do + expect(profile.idv_level).to eql('legacy_in_person') + end end - it 'marks the profile as legacy_in_person' do - expect(profile.idv_level).to eql('legacy_in_person') + end + + context 'with in_person_verification_needed' do + context 'when threatmetrix decisioning is enabled' do + let(:in_person_proofing_enforce_tmx_mock) { true } + + before do + allow(IdentityConfig.store).to receive(:in_person_proofing_enforce_tmx). + and_return(in_person_proofing_enforce_tmx_mock) + allow(IdentityConfig.store).to receive(:proofing_device_profiling). + and_return(:enabled) + end + + let(:profile) do + subject.save_profile( + fraud_pending_reason: nil, + gpo_verification_needed: false, + deactivation_reason: nil, + in_person_verification_needed: true, + selfie_check_performed: false, + ) + end + + it 'creates a pending profile for in person verification' do + expect(profile.activated_at).to be_nil + expect(profile.active).to eq(false) + expect(profile.deactivation_reason).to be_nil + expect(profile.fraud_pending_reason).to be_nil + expect(profile.in_person_verification_pending?).to eq(true) + expect(profile.fraud_review_pending?).to eq(false) + expect(profile.gpo_verification_pending_at.present?).to eq(false) + expect(profile.initiating_service_provider).to eq(nil) + expect(profile.verified_at).to be_nil + end + + it 'marks the profile as in_person' do + expect(profile.idv_level).to eql('in_person') + end end end diff --git a/spec/support/features/document_capture_step_helper.rb b/spec/support/features/document_capture_step_helper.rb index c5ed54a7438..18d2881356a 100644 --- a/spec/support/features/document_capture_step_helper.rb +++ b/spec/support/features/document_capture_step_helper.rb @@ -11,7 +11,7 @@ def attach_and_submit_images submit_images end - def attach_images(file = Rails.root.join('app', 'assets', 'images', 'logo.png')) + def attach_images(file = Rails.root.join('app', 'assets', 'images', 'email', 'logo.png')) attach_file t('doc_auth.headings.document_capture_front'), file, make_visible: true attach_file t('doc_auth.headings.document_capture_back'), file, make_visible: true end @@ -26,7 +26,7 @@ def attach_liveness_images( attach_selfie end - def attach_selfie(file = Rails.root.join('app', 'assets', 'images', 'logo.png')) + def attach_selfie(file = Rails.root.join('app', 'assets', 'images', 'email', 'logo.png')) attach_file t('doc_auth.headings.document_capture_selfie'), file, make_visible: true end diff --git a/spec/support/features/session_helper.rb b/spec/support/features/session_helper.rb index 08ee7c6153f..4658d9ef97a 100644 --- a/spec/support/features/session_helper.rb +++ b/spec/support/features/session_helper.rb @@ -142,12 +142,6 @@ def sign_up user end - def sign_up_with_backup_codes - user = create(:user, :unconfirmed, :with_backup_code) - confirm_last_user - user - end - def sign_up_and_set_password user = sign_up user.password = VALID_PASSWORD @@ -157,13 +151,6 @@ def sign_up_and_set_password user end - def sign_up_with_backup_codes_and_set_password - user = sign_up_with_backup_codes - fill_in t('forms.password'), with: VALID_PASSWORD - click_button t('forms.buttons.continue') - user - end - def sign_in_user(user = create(:user), email = nil) email ||= user.email_addresses.first.email signin(email, user.password) @@ -268,17 +255,6 @@ def sign_in_live_with_2fa(user = user_with_2fa) user end - def sign_in_live_with_piv_cac(user = user_with_piv_cac) - sign_in_user(user) - allow(FeatureManagement).to receive(:development_and_identity_pki_disabled?).and_return(true) - visit login_two_factor_piv_cac_path - stub_piv_cac_service - visit_piv_cac_service( - dn: 'C=US, O=U.S. Government, OU=DoD, OU=PKI, CN=DOE.JOHN.1234', - uuid: user.piv_cac_configurations.first.x509_dn_uuid, - ) - end - def fill_in_code_with_last_phone_otp accept_rules_of_use_and_continue_if_displayed fill_in I18n.t('components.one_time_code_input.label'), with: last_phone_otp @@ -317,11 +293,6 @@ def click_agree_and_continue_optional click_button t('sign_up.agree_and_continue') end - def enter_correct_otp_code_for_user(user) - fill_in 'code', with: user.reload.direct_otp - click_submit_default - end - def perform_in_browser(name) old_session = Capybara.session_name Capybara.session_name = name @@ -329,18 +300,7 @@ def perform_in_browser(name) Capybara.session_name = old_session end - def sign_in_with_totp_enabled_user - user = build(:user, :fully_registered, :with_authentication_app, password: VALID_PASSWORD) - sign_in_user(user) - fill_in 'code', with: generate_totp_code(@secret) - click_submit_default - end - def acknowledge_and_confirm_personal_key - click_acknowledge_personal_key - end - - def click_acknowledge_personal_key checkbox_header = t('forms.personal_key.required_checkbox') find('label', text: /#{checkbox_header}/).click click_continue @@ -413,7 +373,8 @@ def sign_up_user_from_sp_without_confirming_email(email) attempt_to_confirm_email_with_invalid_token(sp_request_id) - expect(current_url).to eq sign_up_email_resend_url(request_id: sp_request_id) + expect(page).to have_current_path sign_up_register_path(request_id: sp_request_id) + expect(page).to have_content t('errors.messages.confirmation_invalid_token') submit_resend_email_confirmation_form_with_correct_email(email) @@ -478,7 +439,8 @@ def attempt_to_confirm_email_with_invalid_token(request_id) def submit_resend_email_confirmation_form_with_correct_email(email) fill_in t('forms.registration.labels.email'), with: email - click_button t('forms.buttons.resend_confirmation') + check t('sign_up.terms', app_name: APP_NAME) + click_submit_default end def click_confirmation_link_in_email(email) @@ -558,15 +520,6 @@ def set_up_2fa_with_authenticator_app click_button 'Submit' end - def set_up_2fa_with_backup_codes - select_2fa_option('backup_code') - - expect(page).to have_current_path backup_code_setup_path - - check t('forms.backup_code.saved') - click_button 'Continue' - end - def register_user_with_piv_cac(email = 'test@test.com') confirm_email_and_password(email) expect(page).to have_current_path authentication_methods_setup_path @@ -683,22 +636,11 @@ def click_reset_password_link_from_email expect(current_path).to eq edit_user_password_path end - def fill_reset_password_form - fill_in t('forms.passwords.edit.labels.password'), with: 'newVal!dPassw0rd' - click_button t('forms.passwords.edit.buttons.submit') - - expect(current_path).to eq new_user_session_path - end - def expect_branded_experience # Check for branded experience as being the header containing the Login.gov and partner logos expect(page).to have_css(".page-header--basic img[alt='#{APP_NAME}'] ~ img") end - def acknowledge_backup_code_confirmation - click_on t('two_factor_authentication.backup_codes.saved_backup_codes') - end - def set_hidden_field(id, value) input = first("input##{id}", visible: false) if javascript_enabled? diff --git a/spec/views/idv/address/new.html.erb_spec.rb b/spec/views/idv/address/new.html.erb_spec.rb index 82d6f818c1c..2e2b7e0912f 100644 --- a/spec/views/idv/address/new.html.erb_spec.rb +++ b/spec/views/idv/address/new.html.erb_spec.rb @@ -4,7 +4,8 @@ let(:parsed_page) { Nokogiri::HTML.parse(rendered) } before do - assign(:presenter, Idv::AddressPresenter.new(pii: {})) + assign(:presenter, Idv::AddressPresenter.new) + assign(:address_form, Idv::AddressForm.new({})) render end diff --git a/spec/views/sign_up/email_resend/new.html.erb_spec.rb b/spec/views/sign_up/email_resend/new.html.erb_spec.rb deleted file mode 100644 index fc5b5450542..00000000000 --- a/spec/views/sign_up/email_resend/new.html.erb_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'sign_up/email_resend/new.html.erb' do - before do - @user = User.new - @resend_email_confirmation_form = ResendEmailConfirmationForm.new - end - - it 'has a localized title' do - expect(view).to receive(:title=).with(t('titles.confirmations.new')) - - render - end - - it 'has a localized header' do - render - - expect(rendered).to have_selector('h1', text: t('headings.confirmations.new')) - end -end