A Guide for Upgrading Ruby on Rails¶ ↑
This guide provides steps to be followed when you upgrade your applications to a newer version of Ruby on Rails. These steps are also available in individual release guides.
General Advice¶ ↑
Before attempting to upgrade an existing application, you should be sure you have a good reason to upgrade. You need to balance several factors: the need for new features, the increasing difficulty of finding support for old code, and your available time and skills, to name a few.
Test Coverage¶ ↑
The best way to be sure that your application still works after upgrading is to have good test coverage before you start the process. If you don't have automated tests that exercise the bulk of your application, you'll need to spend time manually exercising all the parts that have changed. In the case of a Rails upgrade, that will mean every single piece of functionality in the application. Do yourself a favor and make sure your test coverage is good before you start an upgrade.
Ruby Versions¶ ↑
Rails generally stays close to the latest released Ruby version when it's released:
-
Rails 3 and above require Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially. You should upgrade as early as possible.
-
Rails 3.2.x is the last branch to support Ruby 1.8.7.
-
Rails 4 prefers Ruby 2.0 and requires 1.9.3 or newer.
TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing.
The Rake Task¶ ↑
Rails provides the rails:update
rake task. After updating the
Rails version in the Gemfile, run this rake task. This will help you with
the creation of new files and changes of old files in an interactive
session.
$ rake rails:update identical config/boot.rb exist config conflict config/routes.rb Overwrite /myapp/config/routes.rb? (enter "h" for help) [Ynaqdh] force config/routes.rb conflict config/application.rb Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh] force config/application.rb conflict config/environment.rb ...
Don't forget to review the difference, to see if there were any unexpected changes.
Upgrading from Rails 4.1 to Rails 4.2¶ ↑
Web Console¶ ↑
First, add gem 'web-console', '~> 2.0'
to
the :development
group in your Gemfile and run bundle
install
(it won't have been included when you upgraded Rails).
Once it's been installed, you can simply drop a reference to the
console helper (i.e., <%= console %>
) into any view you
want to enable it for.
Responders¶ ↑
respond_with
and the class-level respond_to
methods have been extracted to the responders
gem. To use
them, simply add gem 'responders', '~> 2.0'
to your Gemfile. Calls to respond_with
and
respond_to
(again, at the class level) will no longer work
without having included the responders
gem in your
dependencies:
# app/controllers/users_controller.rb class UsersController < ApplicationController respond_to :html, :json def show @user = User.find(params[:id]) respond_with @user end end
Instance-level respond_to
is unaffected and does not require
the additional gem:
# app/controllers/users_controller.rb class UsersController < ApplicationController def show @user = User.find(params[:id]) respond_to do |format| format.html format.json { render json: @user } end end end
See #16526 for more details.
Error handling in transaction callbacks¶ ↑
Currently, Active Record suppresses errors raised within
after_rollback
or after_commit
callbacks and only
prints them to the logs. In the next version, these errors will no longer
be suppressed. Instead, the errors will propagate normally just like in
other Active Record callbacks.
When you define a after_rollback
or after_commit
callback, you will receive a deprecation warning about this upcoming
change. When you are ready, you can opt into the new behavior and remove
the deprecation warning by adding following configuration to your
config/application.rb
:
config.active_record.raise_in_transactional_callbacks = true
See #14488 and #16537 for more details.
Ordering of test cases¶ ↑
In Rails 5.0, test cases will be executed in random order by default. In
anticipation of this change, Rails 4.2 introduced a new configuration
option active_support.test_order
for explicitly specifying the
test ordering. This allows you to either lock down the current behavior by
setting the option to :sorted
, or opt into the future behavior
by setting the option to :random
.
If you do not specify a value for this option, a deprecation warning will be emitted. To avoid this, add the following line to your test environment:
# config/environments/test.rb Rails.application.configure do config.active_support.test_order = :sorted # or `:random` if you prefer end
Serialized attributes¶ ↑
When using a custom coder (e.g. serialize :metadata, JSON
),
assigning nil
to a serialized attribute will save it to the
database as NULL
instead of passing the nil
value
through the coder (e.g. "null"
when using the
JSON
coder).
Production log level¶ ↑
In Rails 5, the default log level for the production environment will be
changed to :debug
(from :info
). To preserve the
current default, add the following line to your production.rb
:
# Set to `:info` to match the current default, or set to `:debug` to opt-into # the future default. config.log_level = :info
after_bundle
in Rails templates¶ ↑
If you have a Rails template that adds all the files in version control, it fails to add the generated binstubs because it gets executed before Bundler:
# template.rb generate(:scaffold, "person name:string") route "root to: 'people#index'" rake("db:migrate") git :init git add: "." git commit: %Q{ -m 'Initial commit' }
You can now wrap the git
calls in an after_bundle
block. It will be run after the binstubs have been generated.
# template.rb generate(:scaffold, "person name:string") route "root to: 'people#index'" rake("db:migrate") after_bundle do git :init git add: "." git commit: %Q{ -m 'Initial commit' } end
Rails HTML Sanitizer¶ ↑
There's a new choice for sanitizing HTML fragments in your applications. The venerable html-scanner approach is now officially being deprecated in favor of Rails HTML Sanitizer.
This means the methods sanitize
, sanitize_css
,
strip_tags
and strip_links
are backed by a new
implementation.
This new sanitizer uses Loofah internally. Loofah in turn uses Nokogiri, which wraps XML parsers written in both C and Java, so sanitization should be faster no matter which Ruby version you run.
The new version updates sanitize
, so it can take a
Loofah::Scrubber
for powerful scrubbing. See some
examples of scrubbers here.
Two new scrubbers have also been added: PermitScrubber
and
TargetScrubber
. Read the gem’s readme for
more information.
The documentation for PermitScrubber
and
TargetScrubber
explains how you can gain complete control over
when and how elements should be stripped.
If your application needs to use the old sanitizer implementation, include
rails-deprecated_sanitizer
in your Gemfile:
gem 'rails-deprecated_sanitizer'
Rails DOM Testing¶ ↑
The TagAssertions
module (containing methods such as assert_tag
), has
been deprecated in favor of the assert_select
methods from
the SelectorAssertions
module, which has been extracted into
the rails-dom-testing
gem.
Masked Authenticity Tokens¶ ↑
In order to mitigate SSL attacks, form_authenticity_token
is
now masked so that it varies with each request. Thus, tokens are validated
by unmasking and then decrypting. As a result, any strategies for verifying
requests from non-rails forms that relied on a static session CSRF token
have to take this into account.
Action Mailer¶ ↑
Previously, calling a mailer method on a mailer class will result in the
corresponding instance method being executed directly. With the
introduction of Active Job and #deliver_later
, this is no
longer true. In Rails 4.2, the invocation of the instance methods are
deferred until either deliver_now
or
deliver_later
is called. For example:
class Notifier < ActionMailer::Base def notify(user, ...) puts "Called" mail(to: user.email, ...) end end mail = Notifier.notify(user, ...) # Notifier#welcome is not yet called at this point mail = mail.deliver_now # Prints "Called"
This should not result in any noticible differnces for most applications. However, if you need some non-mailer methods to be exectuted synchronously, and you were previously relying on the synchronous proxying behavior, you should define them as class methods on the mailer class directly:
class Notifier < ActionMailer::Base def self.broadcast_notifications(users, ...) users.each { |user| Notifier.notify(user, ...) } end end
Foreign Key Support¶ ↑
The migration DSL has been expanded to support foreign key definitions. If you've been using the Foreigner gem, you might want to consider removing it. Note that the foreign key support of Rails is a subset of Foreigner. This means that not every Foreigner definition can be fully replaced by it's Rails migration DSL counterpart.
The migration procedure is as follows:
-
remove
gem "foreigner"
from the Gemfile. -
run
bundle install
. -
run
bin/rake db:schema:dump
. -
make sure that
db/schema.rb
contains every foreign key definition with the necessary options.
Upgrading from Rails 4.0 to Rails 4.1¶ ↑
CSRF protection from remote <script>
tags¶ ↑
Or, “whaaat my tests are failing!!!?”
Cross-site request forgery (CSRF) protection now covers GET requests with JavaScript responses, too. This prevents a third-party site from referencing your JavaScript URL and attempting to run it to extract sensitive data.
This means that your functional and integration tests that use
get :index, format: :js
will now trigger CSRF protection. Switch to
xhr :get, :index, format: :js
to explicitly test an XmlHttpRequest
.
If you really mean to load JavaScript from remote
<script>
tags, skip CSRF protection on that action.
Spring¶ ↑
If you want to use Spring as your application preloader you need to:
-
Add
gem 'spring', group: :development
to yourGemfile
. -
Install spring using
bundle install
. -
Springify your binstubs with
bundle exec spring binstub --all
.
NOTE: User defined rake tasks will run in the development
environment by default. If you want them to run in other environments
consult the Spring
README.
config/secrets.yml
¶ ↑
If you want to use the new secrets.yml
convention to store
your application's secrets, you need to:
-
Create a
secrets.yml
file in yourconfig
folder with the following content:development: secret_key_base: test: secret_key_base: production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
-
Use your existing
secret_key_base
from thesecret_token.rb
initializer to set the SECRET_KEY_BASE environment variable for whichever users running the Rails application in production mode. Alternatively, you can simply copy the existingsecret_key_base
from thesecret_token.rb
initializer tosecrets.yml
under theproduction
section, replacing '<%= ENV %>'. -
Remove the
secret_token.rb
initializer. -
Use
rake secret
to generate new keys for thedevelopment
andtest
sections. -
Restart your server.
Changes to test helper¶ ↑
If your test helper contains a call to
ActiveRecord::Migration.check_pending!
this can be removed.
The check is now done automatically when you require
'rails/test_help'
, although leaving this line in your helper
is not harmful in any way.
Cookies serializer¶ ↑
Applications created before Rails 4.1 uses Marshal
to
serialize cookie values into the signed and encrypted cookie jars. If you
want to use the new JSON
-based format in your application, you
can add an initializer file with the following content:
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
This would transparently migrate your existing
Marshal
-serialized cookies into the new
JSON
-based format.
When using the :json
or :hybrid
serializer, you
should beware that not all Ruby objects can be serialized as JSON. For
example, Date
and Time
objects will be serialized
as strings, and Hash
es will have their keys stringified.
class CookiesController < ApplicationController def set_cookie cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014 redirect_to action: 'read_cookie' end def read_cookie cookies.encrypted[:expiration_date] # => "2014-03-20" end end
It's advisable that you only store simple data (strings and numbers) in cookies. If you have to store complex objects, you would need to handle the conversion manually when reading the values on subsequent requests.
If you use the cookie session store, this would apply to the
session
and flash
hash as well.
Flash structure changes¶ ↑
Flash message keys are normalized to strings. They can still be accessed using either symbols or strings. Looping through the flash will always yield string keys:
flash["string"] = "a string" flash[:symbol] = "a symbol" # Rails < 4.1 flash.keys # => ["string", :symbol] # Rails >= 4.1 flash.keys # => ["string", "symbol"]
Make sure you are comparing Flash message keys against strings.
Changes in JSON handling¶ ↑
There are a few major changes related to JSON handling in Rails 4.1.
MultiJSON removal¶ ↑
MultiJSON has reached its end-of-life and has been removed from Rails.
If your application currently depend on MultiJSON directly, you have a few options:
-
Add 'multi_json' to your Gemfile. Note that this might cease to work in the future
-
Migrate away from MultiJSON by using
obj.to_json
, andJSON.parse(str)
instead.
WARNING: Do not simply replace MultiJson.dump
and
MultiJson.load
with JSON.dump
and
JSON.load
. These JSON gem APIs are meant for serializing and
deserializing arbitrary Ruby objects and are generally unsafe.
JSON gem compatibility¶ ↑
Historically, Rails had some compatibility issues with the JSON gem. Using
JSON.generate
and JSON.dump
inside a Rails
application could produce unexpected errors.
Rails 4.1 fixed these issues by isolating its own encoder from the JSON gem. The JSON gem APIs will function as normal, but they will not have access to any Rails-specific features. For example:
class FooBar def as_json(options = nil) { foo: 'bar' } end end >> FooBar.new.to_json # => "{\"foo\":\"bar\"}" >> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#<FooBar:0x007fa80a481610>\""
New JSON encoder¶ ↑
The JSON encoder in Rails 4.1 has been rewritten to take advantage of the JSON gem. For most applications, this should be a transparent change. However, as part of the rewrite, the following features have been removed from the encoder:
-
Circular data structure detection
-
Support for the
encode_json
hook -
Option to encode
BigDecimal
objects as numbers instead of strings
If your application depends on one of these features, you can get them back by adding the activesupport-json_encoder gem to your Gemfile.
JSON representation of Time objects¶ ↑
#as_json
for objects with time component (Time
,
DateTime
, ActiveSupport::TimeWithZone
) now
returns millisecond precision by default. If you need to keep old behavior
with no millisecond precision, set the following in an initializer:
ActiveSupport::JSON::Encoding.time_precision = 0
Usage of return
within inline callback blocks¶ ↑
Previously, Rails allowed inline callback blocks to use return
this way:
class ReadOnlyModel < ActiveRecord::Base before_save { return false } # BAD end
This behavior was never intentionally supported. Due to a change in the
internals of ActiveSupport::Callbacks
, this is no longer
allowed in Rails 4.1. Using a return
statement in an inline
callback block causes a LocalJumpError
to be raised when the
callback is executed.
Inline callback blocks using return
can be refactored to
evaluate to the returned value:
class ReadOnlyModel < ActiveRecord::Base before_save { false } # GOOD end
Alternatively, if return
is preferred it is recommended to
explicitly define a method:
class ReadOnlyModel < ActiveRecord::Base before_save :before_save_callback # GOOD private def before_save_callback return false end end
This change applies to most places in Rails where callbacks are used,
including Active Record and Active Model callbacks, as well as filters in
Action Controller (e.g. before_action
).
See this pull request for more details.
Methods defined in Active Record fixtures¶ ↑
Rails 4.1 evaluates each fixture's ERB in a separate context, so helper methods defined in a fixture will not be available in other fixtures.
Helper methods that are used in multiple fixtures should be defined on
modules included in the newly introduced
ActiveRecord::FixtureSet.context_class
, in
test_helper.rb
.
module FixtureFileHelpers def file_sha(path) Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path))) end end ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
I18n enforcing available locales¶ ↑
Rails 4.1 now defaults the I18n option
enforce_available_locales
to true
. This means
that it will make sure that all locales passed to it must be declared in
the available_locales
list.
To disable it (and allow I18n to accept any locale option) add the following configuration to your application:
config.i18n.enforce_available_locales = false
Note that this option was added as a security measure, to ensure user input cannot be used as locale information unless it is previously known. Therefore, it's recommended not to disable this option unless you have a strong reason for doing so.
Mutator methods called on Relation¶ ↑
Relation
no longer has mutator methods like #map!
and #delete_if
. Convert to an Array
by calling
#to_a
before using these methods.
It intends to prevent odd bugs and confusion in code that call mutator
methods directly on the Relation
.
# Instead of this Author.where(name: 'Hank Moody').compact! # Now you have to do this authors = Author.where(name: 'Hank Moody').to_a authors.compact!
Changes on Default Scopes¶ ↑
Default scopes are no longer overridden by chained conditions.
In previous versions when you defined a default_scope
in a
model it was overridden by chained conditions in the same field. Now it is
merged like any other scope.
Before:
class User < ActiveRecord::Base default_scope { where state: 'pending' } scope :active, -> { where state: 'active' } scope :inactive, -> { where state: 'inactive' } end User.all # SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' User.active # SELECT "users".* FROM "users" WHERE "users"."state" = 'active' User.where(state: 'inactive') # SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'
After:
class User < ActiveRecord::Base default_scope { where state: 'pending' } scope :active, -> { where state: 'active' } scope :inactive, -> { where state: 'inactive' } end User.all # SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' User.active # SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active' User.where(state: 'inactive') # SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'
To get the previous behavior it is needed to explicitly remove the
default_scope
condition using unscoped
,
unscope
, rewhere
or except
.
class User < ActiveRecord::Base default_scope { where state: 'pending' } scope :active, -> { unscope(where: :state).where(state: 'active') } scope :inactive, -> { rewhere state: 'inactive' } end User.all # SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' User.active # SELECT "users".* FROM "users" WHERE "users"."state" = 'active' User.inactive # SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'
Rendering content from string¶ ↑
Rails 4.1 introduces :plain
, :html
, and
:body
options to render
. Those options are now
the preferred way to render string-based content, as it allows you to
specify which content type you want the response sent as.
-
render :plain
will set the content type totext/plain
-
render :html
will set the content type totext/html
-
render :body
will not set the content type header.
From the security standpoint, if you don't expect to have any markup in
your response body, you should be using render :plain
as most
browsers will escape unsafe content in the response for you.
We will be deprecating the use of render :text
in a future
version. So please start using the more precise :plain
,
:html
, and :body
options instead. Using
render :text
may pose a security risk, as the content is sent
as text/html
.
PostgreSQL json and hstore datatypes¶ ↑
Rails 4.1 will map json
and hstore
columns to a
string-keyed Ruby Hash
. In earlier versions, a
HashWithIndifferentAccess
was used. This means that symbol
access is no longer supported. This is also the case for
store_accessors
based on top of json
or
hstore
columns. Make sure to use string keys consistently.
Explicit block use for ActiveSupport::Callbacks
¶ ↑
Rails 4.1 now expects an explicit block to be passed when calling
ActiveSupport::Callbacks.set_callback
. This change stems from
ActiveSupport::Callbacks
being largely rewritten for the 4.1
release.
# Previously in Rails 4.0 set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff } # Now in Rails 4.1 set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
Upgrading from Rails 3.2 to Rails 4.0¶ ↑
If your application is currently on any version of Rails older than 3.2.x, you should upgrade to Rails 3.2 before attempting one to Rails 4.0.
The following changes are meant for upgrading your application to Rails 4.0.
HTTP PATCH¶ ↑
Rails 4 now uses PATCH
as the primary HTTP verb for updates
when a RESTful resource is declared in config/routes.rb
. The
update
action is still used, and PUT
requests
will continue to be routed to the update
action as well. So,
if you're using only the standard RESTful routes, no changes need to be
made:
resources :users
<%= form_for @user do |f| %>
class UsersController < ApplicationController def update # No change needed; PATCH will be preferred, and PUT will still work. end end
However, you will need to make a change if you are using
form_for
to update a resource in conjunction with a custom
route using the PUT
HTTP method:
resources :users, do put :update_name, on: :member end
<%= form_for [ :update_name, @user ] do |f| %>
class UsersController < ApplicationController def update_name # Change needed; form_for will try to use a non-existent PATCH route. end end
If the action is not being used in a public API and you are free to change
the HTTP method, you can update your route to use patch
instead of put
:
PUT
requests to /users/:id
in Rails 4 get routed
to update
as they are today. So, if you have an API that gets
real PUT requests it is going to work. The router also routes
PATCH
requests to /users/:id
to the
update
action.
resources :users do patch :update_name, on: :member end
If the action is being used in a public API and you can't change to
HTTP method being used, you can update your form to use the
PUT
method instead:
<%= form_for [ :update_name, @user ], method: :put do |f| %>
For more on PATCH and why this change was made, see this post on the Rails blog.
A note about media types¶ ↑
The errata for the PATCH
verb specifies that
a ‘diff’ media type should be used with PATCH. One such format is JSON Patch. While Rails does
not support JSON Patch natively, it's easy enough to add support:
# in your controller def update respond_to do |format| format.json do # perform a partial update @article.update params[:article] end format.json_patch do # perform sophisticated change end end end # In config/initializers/json_patch.rb: Mime::Type.register 'application/json-patch+json', :json_patch
As JSON Patch was only recently made into an RFC, there aren't a lot of great Ruby libraries yet. Aaron Patterson's hana is one such gem, but doesn't have full support for the last few changes in the specification.
Gemfile¶ ↑
Rails 4.0 removed the assets
group from Gemfile. You'd
need to remove that line from your Gemfile when upgrading. You should also
update your application file (in config/application.rb
):
# Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups)
vendor/plugins¶ ↑
Rails 4.0 no longer supports loading plugins from
vendor/plugins
. You must replace any plugins by extracting
them to gems and adding them to your Gemfile. If you choose not to make
them gems, you can move them into, say, lib/my_plugin/*
and
add an appropriate initializer in
config/initializers/my_plugin.rb
.
Active Record¶ ↑
-
Rails 4.0 has removed the identity map from Active Record, due to some inconsistencies with associations. If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore:
config.active_record.identity_map
. -
The
delete
method in collection associations can now receiveFixnum
orString
arguments as record ids, besides records, pretty much like thedestroy
method does. Previously it raisedActiveRecord::AssociationTypeMismatch
for such arguments. From Rails 4.0 ondelete
automatically tries to find the records matching the given ids before deleting them. -
In Rails 4.0 when a column or a table is renamed the related indexes are also renamed. If you have migrations which rename the indexes, they are no longer needed.
-
Rails 4.0 has changed
serialized_attributes
andattr_readonly
to class methods only. You shouldn't use instance methods since it's now deprecated. You should change them to use class methods, e.g.self.serialized_attributes
toself.class.serialized_attributes
. -
When using the default coder, assigning
nil
to a serialized attribute will save it to the database asNULL
instead of passing thenil
value through YAML ("--- \n...\n"
). -
Rails 4.0 has removed
attr_accessible
andattr_protected
feature in favor of Strong Parameters. You can use the Protected Attributes gem for a smooth upgrade path. -
If you are not using Protected Attributes, you can remove any options related to this gem such as
whitelist_attributes
ormass_assignment_sanitizer
options. -
Rails 4.0 requires that scopes use a callable object such as a Proc or lambda:
scope :active, where(active: true) # becomes scope :active, -> { where active: true }
-
Rails 4.0 has deprecated
ActiveRecord::Fixtures
in favor ofActiveRecord::FixtureSet
. -
Rails 4.0 has deprecated
ActiveRecord::TestCase
in favor ofActiveSupport::TestCase
. -
Rails 4.0 has deprecated the old-style hash based finder API. This means that methods which previously accepted “finder options” no longer do. For example,
Book.find(:all, conditions: { name: '1984' })
has been deprecated in favor ofBook.where(name: '1984')
-
All dynamic methods except for
find_by_...
andfind_by_...!
are deprecated. Here's how you can handle the changes:-
find_all_by_...
becomeswhere(...)
. -
find_last_by_...
becomeswhere(...).last
. -
scoped_by_...
becomeswhere(...)
. -
find_or_initialize_by_...
becomesfind_or_initialize_by(...)
. -
find_or_create_by_...
becomesfind_or_create_by(...)
.
-
-
Note that
where(...)
returns a relation, not an array like the old finders. If you require anArray
, usewhere(...).to_a
. -
These equivalent methods may not execute the same SQL as the previous implementation.
-
To re-enable the old finders, you can use the activerecord-deprecated_finders gem.
-
Rails 4.0 has changed to default join table for
has_and_belongs_to_many
relations to strip the common prefix off the second table name. Any existinghas_and_belongs_to_many
relationship between models with a common prefix must be specified with thejoin_table
option. For example:
CatalogCategory < ActiveRecord::Base has_and_belongs_to_many :catalog_products, join_table: 'catalog_categories_catalog_products' end CatalogProduct < ActiveRecord::Base has_and_belongs_to_many :catalog_categories, join_table: 'catalog_categories_catalog_products' end
-
Note that the the prefix takes scopes into account as well, so relations between
Catalog::Category
andCatalog::Product
orCatalog::Category
andCatalogProduct
need to be updated similarly.
Active Resource¶ ↑
Rails 4.0 extracted Active Resource to its own gem. If you still need the feature you can add the Active Resource gem in your Gemfile.
Active Model¶ ↑
-
Rails 4.0 has changed how errors attach with the
ActiveModel::Validations::ConfirmationValidator
. Now when confirmation validations fail, the error will be attached to:#{attribute}_confirmation
instead ofattribute
. -
Rails 4.0 has changed
ActiveModel::Serializers::JSON.include_root_in_json
default value tofalse
. Now, Active Model Serializers and Active Record objects have the same default behavior. This means that you can comment or remove the following option in theconfig/initializers/wrap_parameters.rb
file:
# Disable root element in JSON by default. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = false # end
Action Pack¶ ↑
-
Rails 4.0 introduces
ActiveSupport::KeyGenerator
and uses this as a base from which to generate and verify signed cookies (among other things). Existing signed cookies generated with Rails 3.x will be transparently upgraded if you leave your existingsecret_token
in place and add the newsecret_key_base
.
# config/initializers/secret_token.rb Myapp::Application.config.secret_token = 'existing secret token' Myapp::Application.config.secret_key_base = 'new secret key base'
Please note that you should wait to set secret_key_base
until
you have 100% of your userbase on Rails 4.x and are reasonably sure you
will not need to rollback to Rails 3.x. This is because cookies signed
based on the new secret_key_base
in Rails 4.x are not
backwards compatible with Rails 3.x. You are free to leave your existing
secret_token
in place, not set the new
secret_key_base
, and ignore the deprecation warnings until you
are reasonably sure that your upgrade is otherwise complete.
If you are relying on the ability for external applications or Javascript
to be able to read your Rails app's signed session cookies (or signed
cookies in general) you should not set secret_key_base
until
you have decoupled these concerns.
-
Rails 4.0 encrypts the contents of cookie-based sessions if
secret_key_base
has been set. Rails 3.x signed, but did not encrypt, the contents of cookie-based session. Signed cookies are “secure” in that they are verified to have been generated by your app and are tamper-proof. However, the contents can be viewed by end users, and encrypting the contents eliminates this caveat/concern without a significant performance penalty.
Please read Pull Request #9978 for details on the move to encrypted session cookies.
-
Rails 4.0 removed the
ActionController::Base.asset_path
option. Use the assets pipeline feature. -
Rails 4.0 has deprecated
ActionController::Base.page_cache_extension
option. UseActionController::Base.default_static_extension
instead. -
Rails 4.0 has removed Action and Page caching from Action Pack. You will need to add the
actionpack-action_caching
gem in order to usecaches_action
and theactionpack-page_caching
to usecaches_pages
in your controllers. -
Rails 4.0 has removed the XML parameters parser. You will need to add the
actionpack-xml_parser
gem if you require this feature. -
Rails 4.0 changes the default
layout
lookup set using symbols or procs that return nil. To get the “no layout” behavior, return false instead of nil. -
Rails 4.0 changes the default memcached client from
memcache-client
todalli
. To upgrade, simply addgem 'dalli'
to yourGemfile
. -
Rails 4.0 deprecates the
dom_id
anddom_class
methods in controllers (they are fine in views). You will need to include theActionView::RecordIdentifier
module in controllers requiring this feature. -
Rails 4.0 deprecates the
:confirm
option for thelink_to
helper. You should instead rely on a data attribute (e.g.data: { confirm: 'Are you sure?' }
). This deprecation also concerns the helpers based on this one (such aslink_to_if
orlink_to_unless
). -
Rails 4.0 changed how
assert_generates
,assert_recognizes
, andassert_routing
work. Now all these assertions raiseAssertion
instead ofActionController::RoutingError
. -
Rails 4.0 raises an
ArgumentError
if clashing named routes are defined. This can be triggered by explicitly defined named routes or by theresources
method. Here are two examples that clash with routes namedexample_path
:
get 'one' => 'test#example', as: :example get 'two' => 'test#example', as: :example
resources :examples get 'clashing/:id' => 'test#example', as: :example
In the first case, you can simply avoid using the same name for multiple
routes. In the second, you can use the only
or
except
options provided by the resources
method
to restrict the routes created as detailed in the Routing Guide.
-
Rails 4.0 also changed the way unicode character routes are drawn. Now you can draw unicode character routes directly. If you already draw such routes, you must change them, for example:
get Rack::Utils.escape('こんにちは'), controller: 'welcome', action: 'index'
becomes
get 'こんにちは', controller: 'welcome', action: 'index'
-
Rails 4.0 requires that routes using
match
must specify the request method. For example:
# Rails 3.x match '/' => 'root#index' # becomes match '/' => 'root#index', via: :get # or get '/' => 'root#index'
-
Rails 4.0 has removed
ActionDispatch::BestStandardsSupport
middleware,<!DOCTYPE html>
already triggers standards mode per msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx and ChromeFrame header has been moved toconfig.action_dispatch.default_headers
.
Remember you must also remove any references to the middleware from your application code, for example:
# Raise exception config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport)
Also check your environment settings for
config.action_dispatch.best_standards_support
and remove it if
present.
-
In Rails 4.0, precompiling assets no longer automatically copies non-JS/CSS assets from
vendor/assets
andlib/assets
. Rails application and engine developers should put these assets inapp/assets
or configureconfig.assets.precompile
. -
In Rails 4.0,
ActionController::UnknownFormat
is raised when the action doesn't handle the request format. By default, the exception is handled by responding with 406 Not Acceptable, but you can override that now. In Rails 3, 406 Not Acceptable was always returned. No overrides. -
In Rails 4.0, a generic
ActionDispatch::ParamsParser::ParseError
exception is raised whenParamsParser
fails to parse request params. You will want to rescue this exception instead of the low-levelMultiJson::DecodeError
, for example. -
In Rails 4.0,
SCRIPT_NAME
is properly nested when engines are mounted on an app that's served from a URL prefix. You no longer have to setdefault_url_options[:script_name]
to work around overwritten URL prefixes. -
Rails 4.0 deprecated
ActionController::Integration
in favor ofActionDispatch::Integration
. -
Rails 4.0 deprecated
ActionController::IntegrationTest
in favor ofActionDispatch::IntegrationTest
. -
Rails 4.0 deprecated
ActionController::PerformanceTest
in favor ofActionDispatch::PerformanceTest
. -
Rails 4.0 deprecated
ActionController::AbstractRequest
in favor ofActionDispatch::Request
. -
Rails 4.0 deprecated
ActionController::Request
in favor ofActionDispatch::Request
. -
Rails 4.0 deprecated
ActionController::AbstractResponse
in favor ofActionDispatch::Response
. -
Rails 4.0 deprecated
ActionController::Response
in favor ofActionDispatch::Response
. -
Rails 4.0 deprecated
ActionController::Routing
in favor ofActionDispatch::Routing
.
Active Support¶ ↑
Rails 4.0 removes the j
alias for
ERB::Util#json_escape
since j
is already used for
ActionView::Helpers::JavaScriptHelper#escape_javascript
.
Helpers Loading Order¶ ↑
The order in which helpers from more than one directory are loaded has
changed in Rails 4.0. Previously, they were gathered and then sorted
alphabetically. After upgrading to Rails 4.0, helpers will preserve the
order of loaded directories and will be sorted alphabetically only within
each directory. Unless you explicitly use the helpers_path
parameter, this change will only impact the way of loading helpers from
engines. If you rely on the ordering, you should check if correct methods
are available after upgrade. If you would like to change the order in which
engines are loaded, you can use config.railties_order=
method.
Active Record Observer and Action Controller Sweeper¶ ↑
ActiveRecord::Observer
and
ActionController::Caching::Sweeper
have been extracted to the
rails-observers
gem. You will need to add the
rails-observers
gem if you require these features.
sprockets-rails¶ ↑
-
assets:precompile:primary
andassets:precompile:all
have been removed. Useassets:precompile
instead. -
The
config.assets.compress
option should be changed toconfig.assets.js_compressor
like so for instance:
config.assets.js_compressor = :uglifier
sass-rails¶ ↑
-
asset-url
with two arguments is deprecated. For example:asset-url("rails.png", image)
becomesasset-url("rails.png")
.
Upgrading from Rails 3.1 to Rails 3.2¶ ↑
If your application is currently on any version of Rails older than 3.1.x, you should upgrade to Rails 3.1 before attempting an update to Rails 3.2.
The following changes are meant for upgrading your application to the latest 3.2.x version of Rails.
Gemfile¶ ↑
Make the following changes to your Gemfile
.
gem 'rails', '3.2.18' group :assets do gem 'sass-rails', '~> 3.2.6' gem 'coffee-rails', '~> 3.2.2' gem 'uglifier', '>= 1.0.3' end
config/environments/development.rb¶ ↑
There are a couple of new configuration settings that you should add to your development environment:
# Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) config.active_record.auto_explain_threshold_in_seconds = 0.5
config/environments/test.rb¶ ↑
The mass_assignment_sanitizer
configuration setting should
also be be added to config/environments/test.rb
:
# Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict
vendor/plugins¶ ↑
Rails 3.2 deprecates vendor/plugins
and Rails 4.0 will remove
them completely. While it's not strictly necessary as part of a Rails
3.2 upgrade, you can start replacing any plugins by extracting them to gems
and adding them to your Gemfile. If you choose not to make them gems, you
can move them into, say, lib/my_plugin/*
and add an
appropriate initializer in config/initializers/my_plugin.rb
.
Active Record¶ ↑
Option :dependent => :restrict
has been removed from
belongs_to
. If you want to prevent deleting the object if
there are any associated objects, you can set :dependent =>
:destroy
and return false
after checking for existence
of association from any of the associated object's destroy callbacks.
Upgrading from Rails 3.0 to Rails 3.1¶ ↑
If your application is currently on any version of Rails older than 3.0.x, you should upgrade to Rails 3.0 before attempting an update to Rails 3.1.
The following changes are meant for upgrading your application to Rails 3.1.12, the last 3.1.x version of Rails.
Gemfile¶ ↑
Make the following changes to your Gemfile
.
gem 'rails', '3.1.12' gem 'mysql2' # Needed for the new asset pipeline group :assets do gem 'sass-rails', '~> 3.1.7' gem 'coffee-rails', '~> 3.1.1' gem 'uglifier', '>= 1.0.3' end # jQuery is the default JavaScript library in Rails 3.1 gem 'jquery-rails'
config/application.rb¶ ↑
The asset pipeline requires the following additions:
config.assets.enabled = true config.assets.version = '1.0'
If your application is using an “/assets” route for a resource you may want change the prefix used for assets to avoid conflicts:
# Defaults to '/assets' config.assets.prefix = '/asset-files'
config/environments/development.rb¶ ↑
Remove the RJS setting config.action_view.debug_rjs = true
.
Add these settings if you enable the asset pipeline:
# Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true
config/environments/production.rb¶ ↑
Again, most of the changes below are for the asset pipeline. You can read more about these in the Asset Pipeline guide.
# Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true # Defaults to Rails.root.join("public/assets") # config.assets.manifest = YOUR_PATH # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # config.assets.precompile += %w( search.js ) # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true
config/environments/test.rb¶ ↑
You can help test performance with these additions to your test environment:
# Configure static asset server for tests with Cache-Control for performance config.serve_static_files = true config.static_cache_control = 'public, max-age=3600'
config/initializers/wrap_parameters.rb¶ ↑
Add this file with the following contents, if you wish to wrap parameters into a nested hash. This is on by default in new applications.
# Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] end # Disable root element in JSON by default. ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end
config/initializers/session_store.rb¶ ↑
You need to change your session key to something new, or remove all sessions:
# in config/initializers/session_store.rb AppName::Application.config.session_store :cookie_store, key: 'SOMETHINGNEW'
or
$ bin/rake db:sessions:clear
Remove :cache and :concat options in asset helpers references in views¶ ↑
-
With the Asset Pipeline the :cache and :concat options aren't used anymore, delete these options from your views.


|
||||||||||
| PREV LETTER NEXT LETTER | FRAMES NO FRAMES |
hivemind.lib.ChainBuilder
, a service which can assemble an
implementation based on a command interface, and an ordered list of objects implementing that
interface (the "commands").ChainFactory
.ChainBuilder
.
|
||||||||||
| PREV LETTER NEXT LETTER | FRAMES NO FRAMES |


|
JTS Topology Suite version 1.13 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object com.vividsolutions.jts.operation.distance3d.AxisPlaneCoordinateSequence
public class AxisPlaneCoordinateSequence
A CoordinateSequence wrapper which projects 3D coordinates into one of the three Cartesian axis planes, using the standard orthonormal projection (i.e. simply selecting the appropriate ordinates into the XY ordinates). The projected data is represented as 2D coordinates.
| Field Summary |
|---|
| Fields inherited from interface com.vividsolutions.jts.geom.CoordinateSequence |
|---|
M, X, Y, Z |
| Method Summary | |
|---|---|
java.lang.Object |
clone()
Returns a deep copy of this collection. |
Envelope |
expandEnvelope(Envelope env)
Expands the given Envelope to include the coordinates in the sequence. |
Coordinate |
getCoordinate(int i)
Returns (possibly a copy of) the i'th coordinate in this sequence. |
void |
getCoordinate(int index,
Coordinate coord)
Copies the i'th coordinate in the sequence to the supplied Coordinate . |
Coordinate |
getCoordinateCopy(int i)
Returns a copy of the i'th coordinate in this sequence. |
int |
getDimension()
Returns the dimension (number of ordinates in each coordinate) for this sequence. |
double |
getOrdinate(int index,
int ordinateIndex)
Returns the ordinate of a coordinate in this sequence. |
double |
getX(int index)
Returns ordinate X (0) of the specified coordinate. |
double |
getY(int index)
Returns ordinate Y (1) of the specified coordinate. |
double |
getZ(int index)
|
static CoordinateSequence |
projectToXY(CoordinateSequence seq)
Creates a wrapper projecting to the XY plane. |
static CoordinateSequence |
projectToXZ(CoordinateSequence seq)
Creates a wrapper projecting to the XZ plane. |
static CoordinateSequence |
projectToYZ(CoordinateSequence seq)
Creates a wrapper projecting to the YZ plane. |
void |
setOrdinate(int index,
int ordinateIndex,
double value)
Sets the value for a given ordinate of a coordinate in this sequence. |
int |
size()
Returns the number of coordinates in this sequence. |
Coordinate[] |
toCoordinateArray()
Returns (possibly copies of) the Coordinates in this collection. |
| Methods inherited from class java.lang.Object |
|---|
equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Method Detail |
|---|
public static CoordinateSequence projectToXY(CoordinateSequence seq)
seq
- the sequence to be projected
public static CoordinateSequence projectToXZ(CoordinateSequence seq)
seq
- the sequence to be projected
public static CoordinateSequence projectToYZ(CoordinateSequence seq)
seq
- the sequence to be projected
public int getDimension()
CoordinateSequence
getDimension
in interface CoordinateSequence
public Coordinate getCoordinate(int i)
CoordinateSequence
Note that in the future the semantics of this method may change to guarantee that the Coordinate returned is always a copy. Callers should not to assume that they can modify a CoordinateSequence by modifying the object returned by this method.
getCoordinate
in interface CoordinateSequence
i
- the index of the coordinate to retrieve
public Coordinate getCoordinateCopy(int i)
CoordinateSequence
getCoordinateCopy
in interface CoordinateSequence
i
- the index of the coordinate to retrieve
public void getCoordinate(int index, Coordinate coord)
CoordinateSequence
Coordinate
. Only the first two dimensions are copied.
getCoordinate
in interface CoordinateSequence
index
- the index of the coordinate to copycoord
- a Coordinate
to receive the valuepublic double getX(int index)
CoordinateSequence
getX
in interface CoordinateSequence
public double getY(int index)
CoordinateSequence
getY
in interface CoordinateSequence
public double getZ(int index)
public double getOrdinate(int index, int ordinateIndex)
CoordinateSequence
getOrdinate
in interface CoordinateSequence
index
- the coordinate index in the sequenceordinateIndex
- the ordinate index in the coordinate (in range [0, dimension-1])public int size()
CoordinateSequence
size
in interface CoordinateSequence
public void setOrdinate(int index, int ordinateIndex, double value)
CoordinateSequence
setOrdinate
in interface CoordinateSequence
index
- the coordinate index in the sequenceordinateIndex
- the ordinate index in the coordinate (in range [0, dimension-1])value
- the new ordinate valuepublic Coordinate[] toCoordinateArray()
CoordinateSequence
toCoordinateArray
in interface CoordinateSequence
public Envelope expandEnvelope(Envelope env)
CoordinateSequence
Envelope
to include the coordinates in the sequence.
Allows implementing classes to optimize access to coordinate values.
expandEnvelope
in interface CoordinateSequence
env
- the envelope to expand
public java.lang.Object clone()
CoordinateSequence
clone
in interface CoordinateSequence
clone
in class java.lang.Object
|
JTS Topology Suite version 1.13 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


No page exists at this address (except for this page to tell you that there is no page here, but that means a page does exist, but there isn't a useful page at this address, well, that is unless you regard this page to be useful).
Click here to go back to the home page.


Choose to dine from all of your favourite restaurents, in the comfort of your own location. Discover new places, new cultures,
and new culsine. Whether you're at home, the office, or a special gathering your options are endless
with CrashMeal. You order, we deliver.
Crash Delivery
CrashMeal is a quick way to get fresh, quality food from the restaurant to you. Whether it is from multiple restaurants or
just one. Streamlined and efficient are what you need, and we get it!. Don't stand in line when you can
order online!


Image of Spiral Galaxy NGC 1300 from Hubble Site
A test showing zooming in to a small image. This canvas has a gradient background set with CSS but could just as easily be transparent.


Fred Ojure's Profile Page
Basic Information
Basic information about me:
Software Projects
Implementation Projects:
Other Information
Contacts:
Hobbies
Sports:


| BAG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BAG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BAG | | BBC | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BBC | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BBC | | BCA | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCA | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCA | | BCF | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCF | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCF | | BCP | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCP | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCP | | BDA | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDA | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDA | | BDD | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDD | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDD | | BDG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDG | | BDI | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDI | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDI | | BDM | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDM | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDM | | BDT | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDT | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDT | | BDX | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDX | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDX | | BFG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFG | | BFM | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFM | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFM | | BFN | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFN | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFN | | BGR | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BGR | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BGR | | BII | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BII | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BII | | BIM | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BIM | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BIM | | BMM | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMM | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMM | | BMO | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMO | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMO | | BNG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BNG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BNG | | BOC | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOC | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOC | | BOG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOG | | BPG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPG | | BPM | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPM | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPM | | BPS | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPS | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPS | | BPT | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPT | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPT | | BR | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BR | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BR | | BRG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BRG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BRG | | BSG | | 1 (Type/Class) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BSG | | 2 (Data Constructor) | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BSG | | BinHandle | OpenAFP, OpenAFP.Internals, OpenAFP.Internals.Binary | | Binary | OpenAFP, OpenAFP.Internals, OpenAFP.Internals.Binary | | Buf | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buf0 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buf1 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buf2 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buffer0 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buffer1 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | Buffer2 | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | bag | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BAG | | bag_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BAG | | bag_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BAG | | bbc | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BBC | | bbc_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BBC | | bbc_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BBC | | bca | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCA | | bca_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCA | | bca_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCA | | bcf | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCF | | bcf_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCF | | bcf_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCF | | bcp | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCP | | bcp_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCP | | bcp_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BCP | | bda | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDA | | bda_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDA | | bda_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDA | | bdd | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDD | | bdd_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDD | | bdd_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDD | | bdg | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDG | | bdg_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDG | | bdg_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDG | | bdi | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDI | | bdi_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDI | | bdi_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDI | | bdm | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDM | | bdm_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDM | | bdm_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDM | | bdt | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDT | | bdt_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDT | | bdt_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDT | | bdx | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDX | | bdx_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDX | | bdx_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BDX | | bfg | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFG | | bfg_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFG | | bfg_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFG | | bfm | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFM | | bfm_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFM | | bfm_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFM | | bfn | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFN | | bfn_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFN | | bfn_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BFN | | bgr | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BGR | | bgr_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BGR | | bgr_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BGR | | bii_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BII | | bii_ImageObjectName | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BII | | bii_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BII | | bim | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BIM | | bim_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BIM | | bim_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BIM | | bmm | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMM | | bmm_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMM | | bmm_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMM | | bmo | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMO | | bmo_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMO | | bmo_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BMO | | bng | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BNG | | bng_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BNG | | bng_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BNG | | boc | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOC | | boc_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOC | | boc_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOC | | bog | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOG | | bog_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOG | | bog_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BOG | | bpg | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPG | | bpg_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPG | | bpg_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPG | | bpm | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPM | | bpm_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPM | | bpm_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPM | | bps | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPS | | bps_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPS | | bps_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPS | | bpt | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPT | | bpt_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPT | | bpt_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BPT | | br | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BR | | br_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BR | | br_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BR | | breakOnGlue | OpenAFP, OpenAFP.Prelude.Exts | | brg | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BRG | | brg_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BRG | | brg_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BRG | | bsg | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BSG | | bsg_ | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BSG | | bsg_Type | OpenAFP, OpenAFP.Records, OpenAFP.Records.AFP, OpenAFP.Records.AFP.BSG | | bufFromPStrLen | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer | | bufOf | OpenAFP, OpenAFP.Internals, OpenAFP.Internals.Binary | | bufToPStrLen | OpenAFP, OpenAFP.Types, OpenAFP.Types.Buffer |
|


2020 Hyundai Sonata Starts At $24,330, Available With Lots Of Upgrades
The range-topping model comes with loads of standard features.
by Chris BruceThe 2020 Hyundai Sonata arrives in the midsized sedan market starting at $24,330 for the base SE grade after the mandatory $930 destination fee. The range-topping Limited goes for $34,230.
The SEL grade comes standard with a 2.5-liter four-cylinder making 191 horsepower (142 kilowatts) and an eight-speed automatic gearbox the provides 32 miles per gallon combined fuel economy. Standard features include a driver safety suite that has forward collision-avoidance assist, lane keep assist, lane follow assist, driver attention warning, automatic high beams, and adaptive cruise control.
Gallery: 2020 Hyundai Sonata (U.S.)
An available convenience package for $1,200 adds useful features like a 12.3-inch digital instrument cluster, wireless device charging, and auto-dimming mirror. As an extra addition with the convenience package, the $1,850 premium package comes with a Bose 12-speaker stereo and heated, leather-wrapped steering wheel.
Wither either of these packages, customers open up the ability to specify the $1,000 panoramic sunroof that includes the transparent top and LED interior lights. Finally, the $950 Drive Guidance system requires the premium pack and sunroof, but it gets buyers a 10.25-inch navigation system and highway drive assist.
More Sonata Variants:
Upgrading to the SEL Plus trim for $28,380 adds a 1.6-liter with 180 hp (134 kW). The only available option is the $2,750 Tech Package that includes the panoramic sunroof, led interior lighting, 10.25-inch navigation display, 12-speaker Bose Stereo, and highway drive assist.
The Limited grade comes all of the available amenities from the other packages. I also adds matrix-type LED headlights. On the inside, there are ventilated front seats, memory for the driver seat and outside mirrors, color head-up display, and a leatherette-wrapped dashboard. Additional safety features include front and rear parking sensors, around-view monitor, remote parking assist, blind-spot view monitor, and rear parking collision avoidance.
Source: Hyundai
Show press release
New 2020 Sonata with Striking Design and Loads of Standard Safety Technology Starting At $23,400
Hyundai announces pricing for the all-new 2020 Sonata
Entry level price only increases $750 easily offset with more content when compared with the 2019 Sonata SE
Sophisticated four-door-coupe look with class-leading front legroom and headroom
New standard Hyundai SmartSense safety and convenience features
ANN ARBOR, Mich. Nov. 7, 2019 – Hyundai Motor America has announced prices for the all-new 2020 Sonata. The completely redesigned 2020 Sonata delivers enhanced fuel efficiency, technology and advanced standard safety features at a starting price of $23,400 for the well- equipped SE model. The value-driven SEL model starts at $25,500 and the top-of-the-line Limited is available for $33,300.
The entry-level SE model comes with new features inside and out, including:
All-new Smartstream 2.5-liter engine with 191 HP (vs. 2019 Sonata SE with 185 HP)
Standard 8-speed automatic transmission and Shift-By-Wire selector (vs. 2019 Sonata SE’s 6-speed)
Combined MPG 32 (vs. 2019 Sonata SE’s 29 MPG)
8-inch LCD monitor (vs 7-inch LCD monitor)
Electronic Parking Brake (new standard SmartSense feature)
Forward Collision-Avoidance Assist (new standard SmartSense feature)
Lane Keeping Assist (LKA) (new standard SmartSense feature)
Lane Follow Assist (LFA) (new standard SmartSense feature)
Driver Attention Warning (DAW) (new standard SmartSense feature)
Automatic high-beam assist (new standard SmartSense feature)
Smart Cruise Control with Stop & Go (new standard SmartSense feature)
LED Hidden Lighting Lamps (new standard SmartSense feature)
LED Daytime Running Lights
LED taillights
Laminated windshield
“With the 2020 Sonata, our focus was a no-compromise innovation approach allowing Sonata owners to have great style, comfort, technology and safety. This focus led to a set of attributes not seen in the midsize car category – attributes such as four-door-coupe looks, 32 mpg, phone as key technology, standard smart cruise control and a class-leading value position,” said Mike O’Brien, vice president, product, corporate and digital planning, Hyundai Motor America. “At Hyundai, we’re big fans of sweating all the details, and we have done that with the 2020 Sonata.”
The Sonata SEL is now equipped with even more design, comfort and convenience features for a value added saving of $750. SEL features include:
Exterior
17-inch alloy wheels
Sport front fascia
Sport rear fascia
Twin-tip muffler
Heated side mirrors
Side mirror turn signal indicators
Interior / Convenience
Proximity key entry with push button start
Hands-free Smart Trunk Release
4.2-inch color LCD instrument cluster display
Leatherette interior door panel inserts
Liquid chrome interior accents
Auto up/down front passenger window
Power driver seat (8-way)
Dual automatic temperature control
Heated front seats
Center rear armrest
Hyundai SmartSense Safety
Blind Spot Collision-Avoidance Assist with Rear Cross-Traffic Collision-Avoidance Assist
Multimedia / Technology
SiriusXM® satellite radio
Blue Link® Connected Car Services (3-years complimentary of Connected Care & Remote
Packages)
SEL option packages provide customers with more choices and the lowest priced panoramic sunroof in the segment.
SEL Convenience Package - $1,200
12.3-inch LCD instrument cluster
Hyundai Digital Key
Wireless device charging
Auto-dimming mirror with HomeLink
Leather-wrapped steering wheel
2nd row air vent
USB charge port (2nd row)
Premium Package - $1,850 (Requires Convenience Package)
Bose® premium audio with 12 speakers
Leather seating surfaces
Heated steering wheel
Panoramic Sunroof - $1,000 (Can be added to SEL Convenience or Premium Packages)
Panoramic sunroof
LED interior lights
Drive Guidance - $950 (Requires Premium and Panoramic Sunroof Package)
10.25-inch Navigation system
Highway Drive Assist
Blue Link Guidance Package (3-Year Complimentary Trial)
The SEL Plus trim is $27,450 and brings sporty exterior upgrades and a new Smartstream1.6-liter
turbocharged engine producing 195 lb.-ft. of torque at a low 1,500–4,500 rpm.
SEL Trim Highlights
Smartstream 1.6T GDI 4-cylinder engine
Paddle shifters
18-inch alloy wheels (machine / gloss black finish)
235/45 R18 Michelin® or Pirelli® tires
Glossy black side mirrors and window surround
Hyundai Digital Key
Aluminum pedals
Dinamica® suede / leatherette seating surfaces
The price of the Sonata Limited is $33,300 and comes with these standout features:
Digital Key - Continuing to promote the latest advances in technology, the new Sonata supports Hyundai Digital Key via a dedicated smartphone app. Hyundai Digital Key utilizes Near Field Communication (NFC) technology, which exhibits a high level of security. The NFC wireless data communication takes place only when the device and the reader are within several centimeters of each other. The Hyundai Digital Key app also allows smartphones to control selected vehicle systems remotely. Using Bluetooth Low Energy (BLE) communication, users can lock and unlock the vehicle, activate the panic alert and start the engine.
Not only does Hyundai Digital Key allow owners to leave traditional keys at home, it also
allows secure sharing of keys with family and friends. The level of access to different vehicle functions can be tailored to each shared key user for a defined period. The vehicle owner can preset the duration of vehicle use or limit the use to only certain features when loaning the vehicle, and, of course, keys can be revoked remotely. For additional convenience in cases such as using a valet service or visiting a Hyundai dealer, Hyundai Digital Key also works with an NFC card, which will be provided with each vehicle. Each Sonata still comes with traditional keys. Digital Key is compatible only with phones using the Android operating system.
Color Head Up Display (HUD) - With a projected image size of eight inches and super- bright clarity (luminance of more than 10,000 candelas per square meter), the Sonata’s HUD provides improved visibility in different lighting conditions. The HUD can be adjusted in both angle and height to provide optimum visibility. The HUD supports driving safety by displaying information such as speed and navigation commands, as well as alerts from active safety and driving assistance features.
Blind-Spot View Monitor with Blind-Spot Collision Warning (BCW) - The Blind-Spot View Monitor with the Sonata’s outside mirror-mounted cameras offers the driver an enhanced field of vision. The Blind-Spot Collision Warning (BCW) system scans for vehicles entering your blind spot. If the driver activates a turn signal, an image of the view from the corresponding wing mirror is displayed in the 12.3-inch cluster display. If a vehicle is detected in the blind spot, audible and visual alerts are provided.
Remote Smart Parking Assist - In a first for its class, the new Sonata offers Remote
Smart Parking Assist to help maneuver the car into or out of parking spaces, boosting convenience for customers. Before a driver attempts to load passengers or luggage, the remote parking function can prove particularly useful, bringing the vehicle out of a tight space. The driver simply uses the smart key to drive the car forward or backward, into or out of a parking space.


Workout
|
Dashboard
Workout Tracker
Workout Routine:
Exercise Type:
Select Exercise Type
Resistance
Cardio
Name:
Distance (miles):
Duration (minutes):
Exercise Name:
Weight (lbs):
Sets:
Reps:
Duration (minutes):
+Add Workout
+Add Another Exercise
Workout Added Successfully!


THE PROOF IS IN THE PUDDING!
Courses done
3+
Projects Completed
13+
Years of experience
1+
MY RECENT WORKS
Bulding and learning complex AI models since 2020


| Created: | 6/27/2020 7:03:26 AM |
| Modified: | 6/27/2020 7:03:26 AM |
| Project: | |
| Advanced: |
| Attribute |
|
Public serial id |
|
Details:
|
|
Public integer program_type_id |
|
Details:
|
|
Public varchar(255) code |
|
Details:
|
|
Public varchar(255) description |
|
Details:
|
|
Public varchar(255) created_by |
|
Details:
|
|
Public varchar(255) updated_by |
|
Details:
|
|
Public timestamp with time zone(0) created_at |
|
Details:
|
|
Public timestamp with time zone(0) updated_at |
|
Details:
|
|
Public timestamp with time zone(0) start_date |
|
Details:
|
|
Public integer fiscal_appropriation_ref |
|
Details:
|
|
Public integer summary_program_type_id |
|
Details:
|
|
Public varchar(255) program |
|
Details:
|
|
Public varchar(255) element |
|
Details:
|
|
Public varchar(255) component |
|
Details:
|
| Operation | ||
|
Public program_type_versions_pkey( id: serial, |
||
|
Details:
<<PK>>
|
||
|
Public program_type_versions_program_type_id_foreign( program_type_id: integer, |
||
|
Details:
<<FK>>
|
| Element | Source Role | Target Role |
|
«table» program_types Table «FK» |
Name: program_type_versions_program_type_id_foreign |
Name: program_types_pkey |
|
Details:
|
| Tag | Value |
| Owner | public |
|
Details:
|
| Property | Value |
| isFinalSpecialization: | 0 |


Fade in Overlay
Hover over the image to see the effect.
Hello World
Opacity with box
Hover over the image to see the effect.
John Doe


Introduction to CartoDB
Woodstock Digital Media FestivalScreen captures from Workshop
I’ll reupload part one on Monday, it looks like it was too big for Vimeo right now. Part I should be okay though!
Who am I
Brief introduction to CartoDB
- Tour of dashboard
- Common data
- Uploading data
- Tour of table and map view
- Publishing maps
- Public profile
Creating your accounts
Set you up with accounts here, https://cartodb.com/signup?plan=academy. This will give you a free upgrade to our student plan, since today, we are all students :)
Your first map in 30 seconds!
Here, we’ll make a map of US counties. You can grab the data from Common Data in your account, you can find the link to Common Data up top.
- Table and map view
- Styling data
- Thematic maps!
Onward!
Your second map!
How to import from a URL. First right click and ‘copy’ this link
Let’s customize our maps
- Basemaps
- Wizards
- Pop ups
- Publishing
Publishing maps
- Visualizations
- Labels and annotations
- Layout
- Publishing options
Your final map!
Let’s import and play with the following,
If you are interested, here is the source
Now, let’s tell a story with it using another tool, Odyssey.js
Markdown
Header
txt
-title: "A history of Indian battles"
-author: "You"
Body
txt
body text
# A history of battles
Explore some of the history of conflict with Native Americans through history.
Battle of Fallen Timbers
1794
General Anthony Wayne (1745-96) led American troops in a battle against a confederation of Native Americans whose leaders included Chief Little Turtle (Miami), Chief Blue Jacket (Shawnee) and Chief Buckongahelas (Lenape). The fighting took place on the Maumee River, near present-day Toledo. source
The battle of Fallen Timbers had ramifications that stretched all the way to Europe. The Treaty of Greenville, negotiated between Wayne and Little Turtle the following year, secured most of what is now Ohio for American settlement. source
Battle of the Little Bighorn
1876
The Battle of the Little Bighorn, commonly referred to as Custer’s Last Stand, was an armed engagement between combined forces of the Lakota, Northern Cheyenne, and Arapaho tribes, against the 7th Cavalry Regiment of the United States Army.
It was an overwhelming victory for the Lakota, Northern Cheyenne, and Arapaho, led by several major war leaders, including Crazy Horse and Chief Gall, inspired by the visions of Sitting Bull. source
Wounded Knee Massacre
Black Elk - medicine man - Oglala Lakota
“I did not know then how much was ended. When I look back now from this high hill of my old age, I can still see the butchered women and children lying heaped and scattered all along the crooked gulch as plain as when I saw them with eyes young.  A people’s dream died there. It was a beautiful dream … the nation’s hope is broken and scattered. There is no center any longer, and the sacred tree is dead.” source
Explore further
Use the map below to explore a full set of battles in the early Americas. Click an point to see the description and date, and find links to search for more information.
txt
Add your layer
Example:
txt
-vizjson: "http://team.cartodb.com/api/v2/viz/a62ff17c-66a1-11e4-a6a3-0e853d047bba/viz.json"
Change a location
Use the interface.
- Zoom the map into the location of Fallen Timbers
- Select ‘add’ and Move map to current location
Custom basemap
Start with the interface button!
Okay, also check out this project, NYPL Map Warper
Tiles:
txt
http://maps.nypl.org/warper/maps/tile/27562/{z}/{x}/{y}.png
Publishing
Click the airplane!


Merchant Name = {{option.device_id?.name}}
Merchant Address = {{option.device_id?.address}}
Referencenumber = {{option.ref}}
Payment Mode = Cash
Merchant Fees Paid = 0
Payment Mode = Card
Merchant Fees Paid ={{addPoint(option.convenience_fee)}}


Update Employee
Employee#:
FirstName:
LastName:
DateofBirth:
Gender:
Address:
Contact No:
SSS:
HDMF:
TIN:


Using the Jenkins Continuous Integration Executables¶
This section describes how to find executables installed by jenkins and how to load the environment to run the application.
Taking COSMO as an example, the first step is to specify a spack spec that identifies an specific build with a set of variants. For example
COSMO_SPEC="cosmo@master%pgi real_type=float cosmo_target=gpu +cppdycore +claw"
Before we can use spack commands, we need to load the spack instance
module load python/3.7.4
. /project/g110/spack/user/tsa/spack/share/spack/setup-env.sh
In order to find the location of that build,
spack location -i ${COSMO_SPEC}
The spec has to be complete and match all variants that were use to build the executable. Jenkins is not building all variant possibilities (it would not be possible). If you need to know the set of variants that are installed, run the following
spack find -v cosmo
==> 8 installed packages
-- linux-rhel7-skylake_avx512 /<EMAIL_ADDRESS>-----------------------
cosmo@master~claw cosmo_target=cpu ~cppdycore~debug+dycoretest+eccodes+parallel~pollen~production real_type=double ~serialize slave=tsa ~verbose
cosmo@master~claw cosmo_target=cpu ~cppdycore~debug+dycoretest+eccodes+parallel~pollen~production real_type=float ~serialize slave=tsa ~verbose
-- linux-rhel7-skylake_avx512 /<EMAIL_ADDRESS>------------------------
cosmo@dev-build~claw cosmo_target=cpu ~cppdycore~debug+dycoretest~eccodes+parallel~pollen~production real_type=float +serialize slave=tsa ~verbose
<EMAIL_ADDRESS>cosmo_target=gpu +cppdycore~debug+eccodes+parallel+pollen+production real_type=double ~serialize slave=tsa ~verbose
<EMAIL_ADDRESS>cosmo_target=gpu +cppdycore~debug+eccodes+parallel+pollen+production real_type=float ~serialize slave=tsa ~verbose
Once you have localized a COSMO executable, you can run it provided you load first the needed environment. In order to use the executable on a compute node, we need first to load the spack module environment for COSMO.
module use /project/g110/modules/admin-tsa/linux-rhel7-skylake_avx512/
source <( spack module tcl loads ${SPACK_SPEC} )
For an example of how to run the COSMO testsuite on the compute nodes of tsa, see Testing COSMO with the Testsuite


Mysterious Wizard:
Thank you.
Since I obtained this thanks to you, allow me to help you in turn. This crystal contains the ancient Melody of the Dark Choir. Recently, I asked a warrior to purify this crystal in the body of a Stakato.
I think you might like to meet that warrior.
Agree.


line-chart
stockTrackAngularJsApp
Directive to create a line chart based off a Symbol's historical data.
<line-chart historical-data="{Array}"> </line-chart>
| Param | Type | Details |
|---|---|---|
| historicalData | Array | An array of historical data |
Parses a date that is friendly to d3
Creates the line chart
Watches the window and renders the line chart
Watches the Symbol historicalData Array and calls the render Function.


Raw assets are any file that doesn't want processing and that will be directly referenced by a page via its URL.
[NWAYO_ROOT]/components/[NAME]/assets/raw/
.[BUILD_ROOT]/raw/[NAME]/
.Files are only copied.
In scripts, the path to these files can be access via app.path.raw
.
In styles, the path to these files can be access via konstan-get('path-raw')
.
Raw files are selected for build via the assets
property of the bundle file.
These tasks interact with the raw files:


(defmacro reader (com fun)
`(set-macro-character ,com
#'(lambda (str _) (declare (ignore _)) (,fun (read str t nil t)))))
After calling (reader #\c fun)
, then if
ever we see c(sex) then (sexp) will be
passes to fun
.
(defmacro reader (com fun)
`(set-macro-character ,com
#'(lambda (str _) (declare (ignore _)) (,fun (read str t nil t)))))
Shorthand for recursive calls to slot-value.
(defmacro ? (s x &rest xs)
(if xs `(? (slot-value ,s ',x) ,@xs) `(slot-value ,s ',x)))
Shorthand for recursive calls to getf
(defmacro ! (s x &rest xs) (if xs `(! (getf ,s ',x) ,@xs) `(getf ,s ',x)))
Anaphoric if (and it
is the anaphoric variable).
(defmacro aif (test yes &optional no) `(let ((it ,test)) (if it ,yes ,no)))
Anaphoric while (and now
is the anaphoric variable).
(defmacro while (expr &body body) `(do ((now ,expr ,expr)) ((not now)) ,@body))
Simpler assert syntax
(defmacro want (x &rest y) `(assert ,x () ,@y))
all colors
(defun color (s c &optional (str t))
(let ((all '((black . 30) (red . 31) (green . 32) (yellow . 33)
(blue . 34) (magenta . 35) (cyan . 36) (white .37))))
(format str "~c[~a;1m~a~c[0m" #\ESC (cdr (assoc c all)) s #\ESC)))
Red, green, yellow
(defun red (s) (color s 'red nil))
(defun green (s) (color s 'green nil))
(defun yellow (s) (color s 'yellow nil))
find anything in lst
(defun has (x &rest lst)
(dolist (y lst) (if (find y x) (return-from has t))))
A counter, implemented as an association list.
If x
is not there, add it in.
Return the incremented value.
(defmacro inca (x a &optional (inc 1))
`(incf (cdr (or (assoc ,x ,a :test #'equal)
(car (setf ,a (cons (cons ,x 0) ,a))))) ,inc))
Entrooy of set of symbols is - sum p*log(p,2)
(defun entropy (a &optional (n 0))
(loop for (_ . v) in a do (incf n v))
(loop for (_ . v) in a sum (* -1 (/ v n) (log (/ v n) 2))))
Return the nth percentile point.
(defun per (a &optional (nth .5) &aux (n (length a)))
(aref a (floor (* nth n))))
The standard deviation is (90th - 10th)/2,56
.
(defun sd (a &optional sorted)
(if sorted
(/ (- (per a .9) (per a .1)) 2.56)
(sd (sort a #'<) t)))
If a string contains a nun, return that num. Else return the string.
(defun num? (s &aux (n (read-from-string s)))
(if (numberp n) n s))
Turn “?” into #?, else, try for a number.
(defun s->cell (s &aux (n (read-from-string s)))
(if (eql "?" s) #\? (num? s)))
Does a symbol name start with b4
?
(defun b4-sym (b4 sym &aux (n (length b4)) (s (symbol-name sym)))
(and (>= (length s) n) (equalp b4 (subseq s 0 n))))
Returns all functions in a package.
(defun funs (&optional (package :common-lisp-user) &aux out)
(aif (find-package package)
(do-all-symbols (s package)
(if (and (fboundp s) (eql it (symbol-package s)))
(push s out))))
out)
(defun timeit (fun &aux (tick internal-time-units-per-second))
(let ((b4 (get-internal-real-time)))
(funcall fun)
(/ (- (get-internal-real-time) b4) tick)))
split strings on commans
(defun s->cells (s &optional (x 0) (y (position #\, s :start (1+ x))))
(cons (s->cell (subseq s x y))
(and y (s->cells s (1+ y)))))
macro for reading csv files
(defmacro with-csv ((lst file &optional out) &body body)
`(progn (csv ,file #'(lambda (,lst) ,@body)) ,out))
function read csv files
(defun csv (file fun)
(with-open-file (str file)
(loop (funcall fun (s->cells (or (read-line str nil)
(return-from csv)))))))
Exit LISP.
(defun halt (&optional (status 0)) (sb-ext:exit :code status))
Get command line
(defun argv () sb-ext:*posix-argv*)
Given a plist with flags
, if the command line
has any of the same keys, then update flags
with the
command-line values.If a flag is all
then print some help.
Flags are grouped
and the the default group is all
.
To change groups, just mention it before mentioning
the flags in that group.
(defun cli (flags &key
(help "help")
(args (cdr (copy-tree (argv))))
(group (getf flags 'all)))
(while (pop args)
(setf now (read-from-string (remove #\- now)))
(cond ((getf group now) (setf (getf group now) (num? (pop args))))
((getf flags now) (setf group (getf flags now)))
((member now group) (setf (getf group now) t))
((equalp now 'h) (format t "~a~%" help))))
flags)
Just to give an example of its use, suppose we run eg-cl
with this command line:
lisp tricks.lisp -loud --dom -k 23 -samples 1
The dashes at the start of the flags are for human
readers (internally, the code just deletes them).
Since the default group is all
, then the
intiial referece to loud
is really all loud
.
Note how once we change goupds (with dom
then
we can set multiple flags in that group.
This will set loud
to true and update the other flags:
> (print (cli '(all (tries 0
fails 0
un nil
seed 10013
data "../data/aaa.csv"
loud nil)
col (p 2)
dom (samples 100
k 23))))
(ALL (FAILS 0
TRIES 0
SEED 11
DATA "../data/aa"
LOUD T
UN NIL)
COL (P 2)
DOM (SAMPLES 100
K 23))
(defun eg.cli(_)
"demo cli"
(pprint (cli '(all (fails 0 tries 0
seed 10013
data "../data/aa"
loud nil un nil)
col (p 2)
dom (samples 100
k 23)))))
I confess that I never found a way to do platform independent random number generation with CommonLisp. So I write my own.
(defvar *seed* 10013)
Return a random integer 0.. n-1.
(defun randi (&optional (n 1)) (floor (* n (/ (randf 1000000.0) 1000000))))
Return a random flaot 0..n-1.
(defun randf (&optional (n 1.0))
(let ((multiplier 16807.0d0)
(modulus<PHONE_NUMBER>.0d0))
(setf *seed* (mod (* multiplier *seed*) modulus))
(* n (- 1.0d0 (/ *seed* modulus)))))
(defmethod print-object ((i thing) str)
(labels
((skip (x)
(and (symbolp x) (equal (elt (symbol-name x) 0) #\_)))
(pairs (s &aux (x (slot-value i s)))
(if x (list s x) (list s)))
(slots (klass)
(remove-if #'skip
(mapcar #'sb-mop:slot-definition-name
(sb-mop:class-slots klass)))))
(format
str "{~a~{ ~a~}}" (class-name (class-of i))
(mapcar #'pairs (sort (slots (class-of i)) #'string<)))))
To run one of the examples eg
, first reset the seed,
take a deep copy of my
(to ensure that any changes ti it
happen isolation.
If un
safe is set, then just run the code.
Else run the code, tracking tries
, fails
.
(defun run (eg my)
(setf my (copy-tree my)
*seed* (! my all seed))
(if (! my all meek)
(funcall eg my)
(multiple-value-bind (_ e)
(ignore-errors (funcall eg my))
(incf (! my all tries))
(cond (e (incf (! my all fails))
(format t "~&~a [~a] ~a~%" (red "✖") eg (yellow e)))
(t (format t "~&~a [~a]~%" (green "✔") eg ))))))
Update my
from the command line.
Run the appropriate test functions (or if eg
is “ls”
then just list everything).
Return to the operating system the number of failures.
(defun main(my &key (package :common-lisp-user) (b4 "EG."))
(let* ((egs (loop for fun in (funs package)
if (b4-sym b4 fun) collect fun))
(my (cli my))
(eg (intern (string-upcase (! my all eg)))))
(case eg
(all (loop for fun in egs do (run fun my)))
(ls (loop for fun in egs do
(format t " :eg ~15a : ~a~%"
fun (or (documentation fun 'function) ""))))
(otherwise (when (member eg egs) (run eg my))))
(halt (! my all fails))))


001/** 002 * Copyright 2014 Tampere University of Technology, Pori Department 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package core.tut.pori.context; 017 018import java.io.IOException; 019 020import javax.servlet.ServletException; 021import javax.servlet.http.HttpServlet; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024import javax.servlet.http.HttpSession; 025 026import org.apache.log4j.Logger; 027import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 028import org.springframework.security.core.Authentication; 029import org.springframework.security.core.context.SecurityContextHolder; 030 031import service.tut.pori.users.UserCore; 032import core.tut.pori.http.Response; 033import core.tut.pori.http.Response.Status; 034import core.tut.pori.users.UserIdentity; 035 036/** 037 * This class handles to basic login/logout functionality and session creation/destruction. 038 * 039 * This class defines the APIs available for client authentication. Note that it is also possible to authenticate by IP address without username or password check, but the functionality must be enabled per IP basis using the front-end system configuration, and is in general recommended only for analysis back-ends. The IP authentication configuration is out of scope for this documentation. 040 * The user authorization is done by checking the presence and validity of a session ID in the header list (cookie) of the executed HTTP request. The session ID can be generated by any of the login methods documented in this specification. It is also possible to provide the authentication details, such as username and password for HTTP basic authentication, for each request, though this is not necessary. 041 * The default configuration prevents multiple logins, and re-authentication will automatically invalidate the previous session, creating a new a session and a new session ID. 042 * 043 * This class is generally bound using web.xml to be outside of REST handler, working independently from the service invocation functionality. 044 */ 045public class LoginHandler extends HttpServlet{ 046 private static final Logger LOGGER = Logger.getLogger(LoginHandler.class); 047 private static final String METHOD_LOGIN = "login"; 048 /** serialization id */ 049 private static final long serialVersionUID =<PHONE_NUMBER>30567889L; 050 051 @Override 052 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 053 handleRequest(req, resp); 054 } 055 056 @Override 057 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 058 handleRequest(req, resp); 059 } 060 061 /** 062 * 063 * @param request 064 * @param response 065 */ 066 private void handleRequest(HttpServletRequest request, HttpServletResponse response){ 067 if(request.getRequestURI().endsWith(METHOD_LOGIN)){ 068 login(getAuthentication(), request, response); 069 }else{ // ther are only two mappings in the web.xml, if this is not login, it must be logout 070 logout(getAuthentication(), request, response); 071 } 072 } 073 074 /** 075 * Login the user using HTTP Basic authentication. Successful authentication attempt will return a new session ID (as a response cookie) that can be used for further authentication. 076 * 077 * @param auth 078 * @param request 079 * @param response 080 */ 081 private void login(Authentication auth, HttpServletRequest request, HttpServletResponse response){ 082 LOGGER.debug("Received login request "+request.getMethod()+" from "+request.getRemoteAddr()); 083 if(auth == null){ 084 new Response(Status.UNAUTHORIZED).writeTo(response); 085 return; 086 } 087 new Response().writeTo(response); 088 } 089 090 /** 091 * Log out the user. This will invalidate the session Id (cookie) currently used by the user. Note that in many cases the only noticeable effect of calling this method is to invalidate the session Id, as most web browsers will automatically re-authenticate the user on any following calls if user credentials are known, thus creating a new session. 092 * 093 * @param auth 094 * @param request 095 * @param response 096 */ 097 private void logout(Authentication auth, HttpServletRequest request, HttpServletResponse response){ 098 LOGGER.debug("Received logout request "+request.getMethod()+" from "+request.getRemoteAddr()); 099 if(auth == null){ 100 LOGGER.debug("User was not logged in."); 101 new Response().writeTo(response); 102 return; 103 } 104 auth.setAuthenticated(false); 105 HttpSession session = request.getSession(false); 106 if(session == null){ 107 LOGGER.debug("No valid session."); 108 }else{ 109 LOGGER.debug("Invalidating session."); 110 session.invalidate(); 111 } 112 113 SecurityContextHolder.clearContext(); 114 new Response().writeTo(response); 115 } 116 117 /** 118 * 119 * @return authentication or null if user has not authenticated 120 */ 121 private Authentication getAuthentication(){ 122 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 123 if(auth != null && auth.isAuthenticated()){ 124 Object principal = auth.getPrincipal(); 125 if(principal.getClass() == UserIdentity.class){ 126 return auth; 127 }else{ 128 LOGGER.debug("UserDetails not available."); 129 } 130 } 131 return null; 132 } 133 134 /** 135 * Set this user as authenticated for the current security context 136 * 137 * @param userId 138 * @throws IllegalArgumentException on bad userId 139 */ 140 public static void authenticate(UserIdentity userId) throws IllegalArgumentException{ 141 userId = UserCore.getUserIdentity(userId.getUserId()); // retrieve all details 142 if(!UserIdentity.isValid(userId)){ 143 throw new IllegalArgumentException("Bad user, id: "+userId.getUserId()); 144 } 145 SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userId, userId.getPassword(), userId.getAuthorities())); 146 } 147}


Reception is open now.
Call at 8am for same day appointments.
Call 111 for help when the surgery is closed. Or find another local NHS service that can help.


Photography¶
Important
I consider myself a landscape photography amateur. I used to have my own camera (Nikon P7100), but now I can only shoot with my cellphone here. The good thing is that for ordinary landscapes, today's cellphones are capable enough to shoot.
My father has always been a heavy camera user, and my mother has always been very keen on appearing in photographs as the main character. As a result, my photography hobby has been influenced by my family to a greater or lesser extent. However, my father always shot portraits, while I prefer to shoot landscapes.
It wasn't until I was pursuing my BS degree in Shanghai that I actually had my first camera by my side that was always with me. It is a Nikon Coolpix P7100, a 10.1 million pixel digital camera with a fixed 35mm-equivalent f/2.8-5.6 28-200mm lens.
Later, my father got a standard DSLR, Nikon D5200, but I didn't play with that camera much. After around 7 years, he updated it to Nikon D780. In fact I still think the mirrorless Nikon Z 6Ⅱ is slightly better in focus and future lenses/firmware supports, but for him DSLR's longer battery life and cheaper large-aperture lens options are much more important.
I didn't bring my camera with me oversea, so I can only show you some photos taken by my cellphones (shot on Google Pixel 5A, image pixels are compressed):


UserName
Password
Keep me logged in
Not a member yet ? Join us
Name
E-mail
DOB
MobileNumber
Address
Already a member ? Go and log in


WITNESS LIST Licensing & Administrative Procedures Committee March 9, 2005-8:00A HB 1045 - Committee Substitute (Goolsby/CSHB1045) For: Madsen, Stephany (American Resort Development) HB 1393 For: Brady, John (Executive Security Management Council/Conoco Phillips) Caldwell, Mark (AIG, Executive Security Management Council) Watson, Ben (Sprint, Corp.) Against: Burt, Bob (Assist) Galloway, Kevin (Assist) Marquis, Robert (Assist) McClure, James (Self and Statewide Patrol, Inc. (State License #B-7692)) Morales, Edgar (Self) Prock, James (Self) Roberts, Walter (Assist/Company) Rodriguez, Gonzalo David (Self) Swearingen, Tom (Self and Licensed Investigator & Swearingen Services) Walker, Dan (Self and Assist) On: Craig, George (Texas Private Security Board)


Front end software engineer who has experience in building and maintaining web-based front-end solutions. Strive to write clean, modular and testable code with consistent code style. Have a natural knack for user experience and pixel-perfect design. Experience with agile development principles and modern JavaScript frameworks, such as REACT. Always customer obsessed!
HTML | CSS | Javascript
jQuery | Node | Express | React | Socket.io | Bootstrap | MaterializeCSS
MongoDB
Shih-Po Bottle is a responsive web site for a bottle company in China
Try it here! | Check out the code!Sketchy is a fun web app that you can pick a random or search GIPHY image as your inspiration to sketch!
Try it here! | Check out the code!Bowser Attack is a web browser game. The goal of the game is to avoid contact with Bowser(Boss) and his fireballs with your curser.
Try it here! | Check out the code!


Maybe you think some data should be available but you can't find it, or maybe you found a way to crash the application. Maybe you'd be really excited if a particular feature is implemented, or maybe you just want to chat. In any case, it would be our privilege to hear from you.
We're fairly certain you know how to get a hold of the software engineering team (e.g., Slack, email, Zoom, Teams, etc), but here are a few additional channels that are out of the ordinary: