SlideShare ist ein Scribd-Unternehmen logo
1 von 11
Downloaden Sie, um offline zu lesen
Full-Text Search
on Heroku . . .
FOR FREE!
(by working around bogons in pg_search)


by Dave Aronson, T. Rex of Codosaurus, LLC
What's the Problem?

:-)   Heroku gives lots of stuff for free.
:-(   But not its full-text search add-ons.
:-)   But we still have the database.
:-(   But using LIKE for that, sucks.
:-)   But PostgreSQL has full text search.
:-(   But that feature is a royal pain to use.
:-)   But the pg_search gem makes it easy.
:-(   But its scopes have problems.
:-)   But I've figured out workarounds.
Example: Job Model

class JobsController < ApplicationController

  def index    # also serves as a search screen

      @jobs = Job.in_category(params[:category]).
                  desc_has(params[:desc]).
                  in_state(params[:state]).
                  title_has(params[:title])
                  # quick and dirty example,
                  # ignoring order and pagination

  end

end
Making pg_search_scopes
class Job < ActiveRecord::Base

  include PgSearch

  attr_accessible :category, :desc, :state, :title

  scope :in_category, lambda { |cat|
    where(category: cat) if cat.present? }

  pg_search_scope :desc_has, against: :desc

  scope :in_state, lambda { |st|
    where(state: st) if st.present? }

  pg_search_scope :title_has, against: :title

end
Bogon #1: Not Optional

- Fails SILENTLY (as far as user knows) --
  no results; only clue is in logs/screen:
Started GET "/jobs" [...]
Processing by JobsController#index as HTML

NOTICE: text-search query doesn't contain lexemes: ""
LINE 1: ...glish', coalesce("jobs"."desc"::text, ''))) @@
('')))

- "query doesn't contain lexemes" means:
 "I need something to search for".
Fix: Wrap it up, I'll take it

class Job < ActiveRecord::Base
  include PgSearch
  attr_accessible :category, :desc, :state, :title
  scope :in_category, lambda { |cat|
    where(category: cat) if cat.present? }
  scope :desc_has, lambda { |desc|
    _desc_has(desc) if desc.present? }
  scope :in_state, lambda { |st|
    where(state: st) if st.present? }
  scope :title_has, lambda { |ttl|
    _title_has(ttl) if ttl.present? }
private
  pg_search_scope :_desc_has, against: :desc
  pg_search_scope :_title_has, against: :title
end
Bogon #2: ONE per Query!
ActiveRecord::StatementInvalid in Jobs#index
Showing /Users/dave/jobboard/app/views/jobs/index.html.erb where line #49 raised:
PG::Error: ERROR: ORDER BY "pg_search_rank" is ambiguous
LINE 1: ...nglish', ''' ' || 'senator' || ' ''')))) ORDER BY pg_search_...
                                                                    ^

- I didn't ask for pg_search_rank!
- Look at the generated SQL:
    SELECT "jobs".*, ([gobbledygook]) AS
    pg_search_rank, "jobs".*, ([similar
    gobbledygook]) AS pg_search_rank FROM
    "jobs" WHERE ([more gobbledygook]) ORDER
    BY pg_search_rank DESC, "jobs"."id" ASC
- It doesn't know which one we want!
Wrong Fix: add .order
class JobsController < ApplicationController
  def index # also serves as a search screen
    @jobs = Job.in_category(params[:category]).
                desc_has(params[:desc]).
                in_state(params[:state]).
                title_has(params[:title]).
                order(:id)
  end
end

- Generated SQL now ends in:
   ORDER BY pg_search_rank DESC,
   "jobs"."id" ASC, id
- Didn't clear; just tacked it on!
Right Fix: add .reorder
class JobsController < ApplicationController
  def index # also serves as a search screen
    @jobs = Job.in_category(params[:category]).
                desc_has(params[:desc]).
                in_state(params[:state]).
                title_has(params[:title]).
                reorder(:id)
  end
end

- Generated SQL now ends in:
   ORDER BY id
- No longer barfs; query now works right.
Summary

To do full-text search for free on Heroku,
you can use pg_search, BUT...

To make its scopes optional, wrap them in
normal scopes with no-argument detection

To use two or more in one query, tack
.reorder onto the query, using a
non-ambiguous column or value
Questions/Contact/Etc.

Any questions?
Contact information:
  YourNameHere.2.trex [at] codosaur [dot] us
   (yes, put your name there, without spaces, punctuation, etc.)
   +1-571-308-6622
   http://www.codosaur.us/ (main site)
   http://blog.codosaur.us/ (code blog)                             Brought to
   http://www.dare2XL.com/ (excellence blog)                          you by
                                                                   Codosaurus,
   http://linkedin.com/in/davearonson                                  LLC
   http://facebook.com/dare2xl
   @davearonson

Weitere ähnliche Inhalte

Mehr von Dave Aronson

Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021Dave Aronson
 
Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021Dave Aronson
 
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020Dave Aronson
 
ACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf PolandACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf PolandDave Aronson
 
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)Dave Aronson
 
ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018Dave Aronson
 
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)Dave Aronson
 

Mehr von Dave Aronson (8)

Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
 
Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021
 
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
 
ACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf PolandACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf Poland
 
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
 
ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018
 
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
 
Ruby Gotchas
Ruby GotchasRuby Gotchas
Ruby Gotchas
 

Kürzlich hochgeladen

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 

Kürzlich hochgeladen (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 

Full text search on Heroku -- for FREE!

  • 1. Full-Text Search on Heroku . . . FOR FREE! (by working around bogons in pg_search) by Dave Aronson, T. Rex of Codosaurus, LLC
  • 2. What's the Problem? :-) Heroku gives lots of stuff for free. :-( But not its full-text search add-ons. :-) But we still have the database. :-( But using LIKE for that, sucks. :-) But PostgreSQL has full text search. :-( But that feature is a royal pain to use. :-) But the pg_search gem makes it easy. :-( But its scopes have problems. :-) But I've figured out workarounds.
  • 3. Example: Job Model class JobsController < ApplicationController def index # also serves as a search screen @jobs = Job.in_category(params[:category]). desc_has(params[:desc]). in_state(params[:state]). title_has(params[:title]) # quick and dirty example, # ignoring order and pagination end end
  • 4. Making pg_search_scopes class Job < ActiveRecord::Base include PgSearch attr_accessible :category, :desc, :state, :title scope :in_category, lambda { |cat| where(category: cat) if cat.present? } pg_search_scope :desc_has, against: :desc scope :in_state, lambda { |st| where(state: st) if st.present? } pg_search_scope :title_has, against: :title end
  • 5. Bogon #1: Not Optional - Fails SILENTLY (as far as user knows) -- no results; only clue is in logs/screen: Started GET "/jobs" [...] Processing by JobsController#index as HTML NOTICE: text-search query doesn't contain lexemes: "" LINE 1: ...glish', coalesce("jobs"."desc"::text, ''))) @@ (''))) - "query doesn't contain lexemes" means: "I need something to search for".
  • 6. Fix: Wrap it up, I'll take it class Job < ActiveRecord::Base include PgSearch attr_accessible :category, :desc, :state, :title scope :in_category, lambda { |cat| where(category: cat) if cat.present? } scope :desc_has, lambda { |desc| _desc_has(desc) if desc.present? } scope :in_state, lambda { |st| where(state: st) if st.present? } scope :title_has, lambda { |ttl| _title_has(ttl) if ttl.present? } private pg_search_scope :_desc_has, against: :desc pg_search_scope :_title_has, against: :title end
  • 7. Bogon #2: ONE per Query! ActiveRecord::StatementInvalid in Jobs#index Showing /Users/dave/jobboard/app/views/jobs/index.html.erb where line #49 raised: PG::Error: ERROR: ORDER BY "pg_search_rank" is ambiguous LINE 1: ...nglish', ''' ' || 'senator' || ' ''')))) ORDER BY pg_search_... ^ - I didn't ask for pg_search_rank! - Look at the generated SQL: SELECT "jobs".*, ([gobbledygook]) AS pg_search_rank, "jobs".*, ([similar gobbledygook]) AS pg_search_rank FROM "jobs" WHERE ([more gobbledygook]) ORDER BY pg_search_rank DESC, "jobs"."id" ASC - It doesn't know which one we want!
  • 8. Wrong Fix: add .order class JobsController < ApplicationController def index # also serves as a search screen @jobs = Job.in_category(params[:category]). desc_has(params[:desc]). in_state(params[:state]). title_has(params[:title]). order(:id) end end - Generated SQL now ends in: ORDER BY pg_search_rank DESC, "jobs"."id" ASC, id - Didn't clear; just tacked it on!
  • 9. Right Fix: add .reorder class JobsController < ApplicationController def index # also serves as a search screen @jobs = Job.in_category(params[:category]). desc_has(params[:desc]). in_state(params[:state]). title_has(params[:title]). reorder(:id) end end - Generated SQL now ends in: ORDER BY id - No longer barfs; query now works right.
  • 10. Summary To do full-text search for free on Heroku, you can use pg_search, BUT... To make its scopes optional, wrap them in normal scopes with no-argument detection To use two or more in one query, tack .reorder onto the query, using a non-ambiguous column or value
  • 11. Questions/Contact/Etc. Any questions? Contact information: YourNameHere.2.trex [at] codosaur [dot] us (yes, put your name there, without spaces, punctuation, etc.) +1-571-308-6622 http://www.codosaur.us/ (main site) http://blog.codosaur.us/ (code blog) Brought to http://www.dare2XL.com/ (excellence blog) you by Codosaurus, http://linkedin.com/in/davearonson LLC http://facebook.com/dare2xl @davearonson