From ebfbc3ebcf765848a83d8a65b8403d787d68a839 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Fri, 6 Aug 2021 17:19:39 -0400 Subject: [PATCH] Work on browser warnings (#380) * bump dev tool * start pruning * pending https://github.com/MiniProfiler/rack-mini-profiler/pull/505 being merged and committed, this removes some warnings * removing console warnings in FF about stylesheet issues * remove alpha warnings * we have fixes for miniprofiler * needed for reference git repo as gem * we should use sessions/new instead of /sessions when we create a new session! * lint * fix tests * lint * ignore resize, we dont seem to use it * and remove it * one more reference * one more place we had index instead of new * remove commented out code * specify the path to favicon, avoiding console message about missing favicon Co-authored-by: epugh@opensourceconnections.com <> --- Gemfile | 4 +- Gemfile.lock | 11 +- README.md | 2 +- app/assets/stylesheets/_qgraph.scss | 14 +- app/assets/stylesheets/bootstrap-add.css | 12 - app/assets/stylesheets/bootstrap.css | 42 +--- app/assets/stylesheets/home.css.scss | 2 +- app/assets/stylesheets/resize.css | 212 ------------------ app/assets/stylesheets/start.css.scss | 1 - app/assets/stylesheets/style.css | 4 - .../authentication/current_user_manager.rb | 2 +- app/controllers/sessions_controller.rb | 7 +- app/controllers/users/signups_controller.rb | 11 +- app/views/layouts/start.html.erb | 1 + .../sessions/{index.html.erb => new.html.erb} | 0 bin/setup_docker | 1 + test/controllers/accounts_controller_test.rb | 2 +- test/controllers/profiles_controller_test.rb | 2 +- test/controllers/sessions_controller_test.rb | 2 +- 19 files changed, 32 insertions(+), 300 deletions(-) delete mode 100644 app/assets/stylesheets/resize.css rename app/views/sessions/{index.html.erb => new.html.erb} (100%) diff --git a/Gemfile b/Gemfile index 9b35f485e..fe96d4c97 100755 --- a/Gemfile +++ b/Gemfile @@ -43,7 +43,9 @@ group :development, :test do gem 'bullet' gem 'byebug' gem 'memory_profiler' - gem 'rack-mini-profiler' + # rubocop:disable Layout/LineLength + gem 'rack-mini-profiler', git: 'https://github.com/MiniProfiler/rack-mini-profiler' # pending release with PR 505 included + # rubocop:enable Layout/LineLength end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index f8923eb6d..3f120b22e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,10 @@ +GIT + remote: https://github.com/MiniProfiler/rack-mini-profiler + revision: 4e6d463b03a6979037171ae2866a85e11fc344df + specs: + rack-mini-profiler (2.3.2) + rack (>= 1.2.0) + GEM remote: https://rubygems.org/ specs: @@ -253,8 +260,6 @@ GEM rack (2.2.3) rack-cors (1.1.1) rack (>= 2.0.0) - rack-mini-profiler (2.3.2) - rack (>= 1.2.0) rack-protection (2.1.0) rack rack-proxy (0.7.0) @@ -421,7 +426,7 @@ DEPENDENCIES puma_worker_killer pundit rack-cors (~> 1.1) - rack-mini-profiler + rack-mini-profiler! rails (= 6.1.4) rails-controller-testing rails-erd (~> 1.6) diff --git a/README.md b/README.md index c6665ad62..8da2d5dbf 100644 --- a/README.md +++ b/README.md @@ -331,7 +331,7 @@ bin/docker r bin/rake db:seed bin/docker r bin/rake db:setup # show routes -bin/docker r bin/rake routes +bin/docker r bin/rails routes # tests bin/docker r bin/rake test diff --git a/app/assets/stylesheets/_qgraph.scss b/app/assets/stylesheets/_qgraph.scss index b3b3b5f79..9e3cf73e5 100644 --- a/app/assets/stylesheets/_qgraph.scss +++ b/app/assets/stylesheets/_qgraph.scss @@ -14,11 +14,11 @@ qgraph { fill: none; stroke-linecap: round; } - + .axis { shape-rendering: crispEdges; } - + .x.axis line { stroke: lightgrey; } @@ -32,25 +32,21 @@ qgraph { fill: none; stroke: #000; } - + line.marker { stroke: blue; stroke-width: 4; stroke-linecap: round; stroke-opacity: 0.3; } - + .qtip { position: absolute; width: 200px; height: auto; padding: 10px; background-color: white; - -webkit-border-radius: 10px; - -moz-border-radius: 10px; border-radius: 10px; - -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); - -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); pointer-events: none; @@ -122,5 +118,3 @@ qgraph { top: 50%; left: 100%; } - - diff --git a/app/assets/stylesheets/bootstrap-add.css b/app/assets/stylesheets/bootstrap-add.css index 2d9b7e2e2..5e7cbd07a 100644 --- a/app/assets/stylesheets/bootstrap-add.css +++ b/app/assets/stylesheets/bootstrap-add.css @@ -112,9 +112,6 @@ a, button, .button { background: -moz-linear-gradient(top, #FFFFFF, #F0F0F0); border: none; border-radius: 0; - -moz-border-radius: 0; - -webkit-border-radius: 0; - -khtml-border-radius: 0; margin-bottom: 0; } @@ -421,9 +418,6 @@ header .dropdown-content li.dropdown-header { right: 19px; font-weight: bold; border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - -khtml-border-radius: 3px; font-size: 16px; } @@ -757,13 +751,7 @@ header .dropdown-content li.dropdown-header { color: #FFF; border: none; border-bottom-left-radius: 3px; - -moz-border-bottom-left-radius: 3px; - -webkit-border-bottom-left-radius: 3px; - -khtml-border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; - -moz-border-bottom-right-radius: 3px; - -webkit-border-bottom-right-radius: 3px; - -khtml-border-bottom-right-radius: 3px; } #dev-settings .btn-submit { diff --git a/app/assets/stylesheets/bootstrap.css b/app/assets/stylesheets/bootstrap.css index 70c89c3a9..75b0031d9 100644 --- a/app/assets/stylesheets/bootstrap.css +++ b/app/assets/stylesheets/bootstrap.css @@ -6,8 +6,7 @@ /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ html { font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; + } body { margin: 0; @@ -230,10 +229,6 @@ th { } p, h2, - h3 { - orphans: 3; - widows: 3; - } h2, h3 { page-break-after: avoid; @@ -2520,7 +2515,7 @@ input[type="search"] { input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; - margin-top: 1px \9; + margin-top: 1px; line-height: normal; } input[type="file"] { @@ -2576,16 +2571,9 @@ output { color: #999; opacity: 1; } -.form-control:-ms-input-placeholder { - color: #999; -} .form-control::-webkit-input-placeholder { color: #999; } -.form-control::-ms-expand { - background-color: transparent; - border: 0; -} .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { @@ -3050,7 +3038,6 @@ select[multiple].input-lg { .btn[disabled], fieldset[disabled] .btn { cursor: not-allowed; - filter: alpha(opacity=65); -webkit-box-shadow: none; box-shadow: none; opacity: .65; @@ -3586,7 +3573,6 @@ tbody.collapse.in { cursor: not-allowed; background-color: transparent; background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); } .open > .dropdown-menu { display: block; @@ -5110,14 +5096,6 @@ a.thumbnail.active { background-position: 0 0; } } -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} @keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5205,7 +5183,6 @@ a.thumbnail.active { .media, .media-body { overflow: hidden; - zoom: 1; } .media-body { width: 10000px; @@ -5848,7 +5825,6 @@ button.list-group-item-danger.active:focus { line-height: 1; color: #000; text-shadow: 0 1px 0 #fff; - filter: alpha(opacity=20); opacity: .2; } .close:hover, @@ -5856,7 +5832,6 @@ button.list-group-item-danger.active:focus { color: #000; text-decoration: none; cursor: pointer; - filter: alpha(opacity=50); opacity: .5; } button.close { @@ -5927,11 +5902,9 @@ button.close { background-color: #000; } .modal-backdrop.fade { - filter: alpha(opacity=0); opacity: 0; } .modal-backdrop.in { - filter: alpha(opacity=50); opacity: .5; } .modal-header { @@ -6008,13 +5981,11 @@ button.close { word-spacing: normal; word-wrap: normal; white-space: normal; - filter: alpha(opacity=0); opacity: 0; line-break: auto; } .tooltip.in { - filter: alpha(opacity=90); opacity: .9; } .tooltip.top { @@ -6256,7 +6227,7 @@ button.close { .carousel-inner > .item > a > img { line-height: 1; } -@media all and (transform-3d), (-webkit-transform-3d) { +@media all { .carousel-inner > .item { -webkit-transition: -webkit-transform .6s ease-in-out; -o-transition: -o-transform .6s ease-in-out; @@ -6328,7 +6299,6 @@ button.close { text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, .6); background-color: rgba(0, 0, 0, 0); - filter: alpha(opacity=50); opacity: .5; } .carousel-control.left { @@ -6336,7 +6306,6 @@ button.close { background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); background-repeat: repeat-x; } .carousel-control.right { @@ -6346,14 +6315,12 @@ button.close { background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); background-repeat: repeat-x; } .carousel-control:hover, .carousel-control:focus { color: #fff; text-decoration: none; - filter: alpha(opacity=90); outline: 0; opacity: .9; } @@ -6547,9 +6514,6 @@ button.close { .affix { position: fixed; } -@-ms-viewport { - width: device-width; -} .visible-xs, .visible-sm, .visible-md, diff --git a/app/assets/stylesheets/home.css.scss b/app/assets/stylesheets/home.css.scss index 45711093e..4f704b425 100644 --- a/app/assets/stylesheets/home.css.scss +++ b/app/assets/stylesheets/home.css.scss @@ -22,7 +22,7 @@ @import "fonts"; @import "panes"; -@import "resize"; +//@import "resize"; # this file here is a candidate for deleting, appears we don't use it. @import "stackedChart"; @import "bootstrap-add"; @import "base"; diff --git a/app/assets/stylesheets/resize.css b/app/assets/stylesheets/resize.css deleted file mode 100644 index 6e991fae5..000000000 --- a/app/assets/stylesheets/resize.css +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Default Layout Theme - * - * Created for jquery.layout - * - * Copyright (c) 2010 - * Fabrizio Balliano (http://www.fabrizioballiano.net) - * Kevin Dalman (http://allpro.net) - * - * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) - * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses. - * - * Last Updated: 2010-02-10 - * NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars - */ - -/* - * PANES & CONTENT-DIVs - */ -.ui-layout-pane { /* all 'panes' */ - border: 1px solid #BBB; - overflow: auto; - /* DO NOT add scrolling (or padding) to 'panes' that have a content-div, - otherwise you may get double-scrollbars - on the pane AND on the content-div - - use ui-layout-wrapper class if pane has a content-div - - use ui-layout-container if pane has an inner-layout - */ - } - /* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */ - .ui-layout-content { - padding: 10px; - position: relative; /* contain floated or positioned elements */ - overflow: auto; /* add scrolling to content-div */ - } - -/* - * UTILITY CLASSES - * Must come AFTER pane-class above so will override - * These classes are NOT auto-generated and are NOT used by Layout - */ -.layout-child-container, -.layout-content-container { - padding: 0; - overflow: hidden; -} -.layout-child-container { - border: 0; /* remove border because inner-layout-panes probably have borders */ -} -.layout-scroll { - overflow: auto; -} -.layout-hide { - display: none; -} - -/* - * RESIZER-BARS - */ -.ui-layout-resizer { /* all 'resizer-bars' */ - background: #DDD; - border: 1px solid #BBB; - border-width: 0; - } - .ui-layout-resizer-drag { /* REAL resizer while resize in progress */ - } - .ui-layout-resizer-hover { /* affects both open and closed states */ - } - /* NOTE: It looks best when 'hover' and 'dragging' are set to the same color, - otherwise color shifts while dragging when bar can't keep up with mouse */ - .ui-layout-resizer-open-hover , /* hover-color to 'resize' */ - .ui-layout-resizer-dragging { /* resizer beging 'dragging' */ - background: #C4E1A4; - } - .ui-layout-resizer-dragging { /* CLONED resizer being dragged */ - border: 1px solid #BBB; - } - .ui-layout-resizer-north-dragging, - .ui-layout-resizer-south-dragging { - border-width: 1px 0; - } - .ui-layout-resizer-west-dragging, - .ui-layout-resizer-east-dragging { - border-width: 0 1px; - } - /* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */ - .ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */ - background: #E1A4A4; /* red */ - } - - .ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */ - background: #EBD5AA; - } - .ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */ - opacity: .10; /* show only a slight shadow */ - filter: alpha(opacity=10); - } - .ui-layout-resizer-sliding-hover { /* sliding resizer - hover */ - opacity: 1.00; /* on-hover, show the resizer-bar normally */ - filter: alpha(opacity=100); - } - /* sliding resizer - add 'outside-border' to resizer on-hover - * this sample illustrates how to target specific panes and states */ - .ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; } - .ui-layout-resizer-south-sliding-hover { border-top-width: 1px; } - .ui-layout-resizer-west-sliding-hover { border-right-width: 1px; } - .ui-layout-resizer-east-sliding-hover { border-left-width: 1px; } - -/* - * TOGGLER-BUTTONS - */ -.ui-layout-toggler { - border: 1px solid #BBB; /* match pane-border */ - background-color: #BBB; - } - .ui-layout-resizer-hover .ui-layout-toggler { - opacity: .60; - filter: alpha(opacity=60); - } - .ui-layout-toggler-hover , /* need when NOT resizable */ - .ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity when IS resizable */ - background-color: #FC6; - opacity: 1.00; - filter: alpha(opacity=100); - } - .ui-layout-toggler-north , - .ui-layout-toggler-south { - border-width: 0 1px; /* left/right borders */ - } - .ui-layout-toggler-west , - .ui-layout-toggler-east { - border-width: 1px 0; /* top/bottom borders */ - } - /* hide the toggler-button when the pane is 'slid open' */ - .ui-layout-resizer-sliding .ui-layout-toggler { - display: none; - } - /* - * style the text we put INSIDE the togglers - */ - .ui-layout-toggler .content { - color: #666; - font-size: 12px; - font-weight: bold; - width: 100%; - padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */ - } - -/* - * PANE-MASKS - * these styles are hard-coded on mask elems, but are also - * included here as !important to ensure will overrides any generic styles - */ -.ui-layout-mask { - border: none !important; - padding: 0 !important; - margin: 0 !important; - overflow: hidden !important; - position: absolute !important; - opacity: 0 !important; - filter: Alpha(Opacity="0") !important; -} -.ui-layout-mask-inside-pane { /* masks always inside pane EXCEPT when pane is an iframe */ - top: 0 !important; - left: 0 !important; - width: 100% !important; - height: 100% !important; -} -div.ui-layout-mask {} /* standard mask for iframes */ -iframe.ui-layout-mask {} /* extra mask for objects/applets */ - -/* - * Default printing styles - */ -@media print { - /* - * Unless you want to print the layout as it appears onscreen, - * these html/body styles are needed to allow the content to 'flow' - */ - html { - height: auto !important; - overflow: visible !important; - } - body.ui-layout-container { - position: static !important; - top: auto !important; - bottom: auto !important; - left: auto !important; - right: auto !important; - /* only IE6 has container width & height set by Layout */ - _width: auto !important; - _height: auto !important; - } - .ui-layout-resizer, .ui-layout-toggler { - display: none !important; - } - /* - * Default pane print styles disables positioning, borders and backgrounds. - * You can modify these styles however it suit your needs. - */ - .ui-layout-pane { - border: none !important; - background: transparent !important; - position: relative !important; - top: auto !important; - bottom: auto !important; - left: auto !important; - right: auto !important; - width: auto !important; - height: auto !important; - overflow: visible !important; - } -} diff --git a/app/assets/stylesheets/start.css.scss b/app/assets/stylesheets/start.css.scss index ed7e31216..75a7b0f52 100644 --- a/app/assets/stylesheets/start.css.scss +++ b/app/assets/stylesheets/start.css.scss @@ -12,6 +12,5 @@ @import "cookies_eu"; @import "fonts"; -@import "resize"; @import "signup"; @import "bootstrap-add"; diff --git a/app/assets/stylesheets/style.css b/app/assets/stylesheets/style.css index d8f67ece2..c3a3b0d27 100644 --- a/app/assets/stylesheets/style.css +++ b/app/assets/stylesheets/style.css @@ -72,8 +72,6 @@ .wiz_new_query { position:relative; background:#369; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; border-radius: 5px; margin: 10px 0 0 10px; display: inline-block; @@ -91,8 +89,6 @@ font-weight: bold; padding: 3px 6px; margin: 0 0 0 10px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; border-radius: 5px; border: none; background: #F0F0F0; diff --git a/app/controllers/concerns/authentication/current_user_manager.rb b/app/controllers/concerns/authentication/current_user_manager.rb index b17208bd6..fd7b14cec 100644 --- a/app/controllers/concerns/authentication/current_user_manager.rb +++ b/app/controllers/concerns/authentication/current_user_manager.rb @@ -43,7 +43,7 @@ def set_current_user end def require_login - redirect_to sessions_path unless @current_user + redirect_to new_session_path unless @current_user end def auto_login user diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 79528efee..b3785108c 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,13 +1,16 @@ # frozen_string_literal: true class SessionsController < ApplicationController - skip_before_action :require_login, only: [ :create, :index ] + skip_before_action :require_login, only: [ :create, :new ] skip_before_action :check_current_user_locked!, only: :create skip_before_action :verify_authenticity_token, only: :create layout 'start' def index + end + + def new @user = User.new end @@ -26,7 +29,7 @@ def create @user.errors.add(:base, 'Unknown email/password combo. Double check you have the correct email address and password, or sign up for a new account.' ) # rubocop:enable Layout/LineLength - format.html { render :index } + format.html { render :new } format.json { render json: { reason: @error }, status: :unprocessable_entity } end end diff --git a/app/controllers/users/signups_controller.rb b/app/controllers/users/signups_controller.rb index 4944933a1..b36e684cb 100644 --- a/app/controllers/users/signups_controller.rb +++ b/app/controllers/users/signups_controller.rb @@ -31,20 +31,11 @@ def create Analytics::Tracker.track_signup_event @user redirect_to root_path else - render template: 'sessions/index' + render template: 'sessions/new' end end format.js end - # respond_to do |format| - # if @user.save - # session[:current_user_id] = @user.id # not sure if we need to do more here? - # Analytics::Tracker.track_signup_event @user - # format.html { redirect_to root_path } - # else - # format.html { render template: 'sessions/index' } - # end - # end end # rubocop:enable Metrics/MethodLength diff --git a/app/views/layouts/start.html.erb b/app/views/layouts/start.html.erb index fa5c4233f..dbbe7de97 100644 --- a/app/views/layouts/start.html.erb +++ b/app/views/layouts/start.html.erb @@ -3,6 +3,7 @@ Quepid -- Relevant Search Solved +<%= favicon_link_tag asset_path "favicon.ico" %> diff --git a/app/views/sessions/index.html.erb b/app/views/sessions/new.html.erb similarity index 100% rename from app/views/sessions/index.html.erb rename to app/views/sessions/new.html.erb diff --git a/bin/setup_docker b/bin/setup_docker index 60ab6cdc6..f749b8af9 100755 --- a/bin/setup_docker +++ b/bin/setup_docker @@ -30,6 +30,7 @@ Dir.chdir APP_ROOT do puts "\n== Building Docker container ==" system "docker-compose up #{build_arg} --no-start" + system "bin/docker r bundle install" # can be removed if we don't reference git repo in Gemfile. system "bin/docker r yarn" system "bin/docker r ./wait-for mysql:3306 -- bin/rake db:setup" system "bin/docker r ./wait-for mysql:3306 -- bin/rake db:create RAILS_ENV=test" diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb index 9ca0b0899..cf7730ce6 100644 --- a/test/controllers/accounts_controller_test.rb +++ b/test/controllers/accounts_controller_test.rb @@ -14,7 +14,7 @@ class AccountsControllerTest < ActionController::TestCase test 'returns an unauthorized error' do patch :update - assert_redirected_to sessions_path + assert_redirected_to new_session_path end end diff --git a/test/controllers/profiles_controller_test.rb b/test/controllers/profiles_controller_test.rb index 747a9fbf5..f9618fd27 100644 --- a/test/controllers/profiles_controller_test.rb +++ b/test/controllers/profiles_controller_test.rb @@ -14,7 +14,7 @@ class ProfilesControllerTest < ActionController::TestCase test 'returns an unauthorized error' do patch :update, params: { user: { name: 'new name' } } - assert_redirected_to sessions_path + assert_redirected_to new_session_path end end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index c9b3cb824..1a967e3df 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -20,7 +20,7 @@ class SessionsControllerTest < ActionController::TestCase post :create, params: { user: { email: 'doug@example.com', password: 'incorrect' }, format: :html } assert_response :success - assert_template 'sessions/index' + assert_template 'sessions/new' # rubocop:disable Layout/LineLength alert_message_template = 'Unknown email/password combo. Double check you have the correct email address and password, or sign up for a new account.'