changeset 154:317821dd92c9 feature_20

Add Embedded plugin, for Doxygen/Javadoc use
author Chris Cannam
date Thu, 27 Jan 2011 09:08:03 +0000
parents e7c03e1738fb
children 1ca23eedd587
files vendor/plugins/embedded/COPYING vendor/plugins/embedded/README vendor/plugins/embedded/RUNNING_TESTS vendor/plugins/embedded/app/controllers/embedded_controller.rb vendor/plugins/embedded/app/helpers/embedded_helper.rb vendor/plugins/embedded/app/views/embedded/index.rhtml vendor/plugins/embedded/app/views/settings/_embedded.rhtml vendor/plugins/embedded/assets/javascripts/rcov.js vendor/plugins/embedded/assets/stylesheets/doxygen.css vendor/plugins/embedded/assets/stylesheets/javadoc.css vendor/plugins/embedded/assets/stylesheets/rcov.css vendor/plugins/embedded/init.rb vendor/plugins/embedded/lib/embedded.rb vendor/plugins/embedded/test/fixtures/html/app-controllers-account_controller_rb.html vendor/plugins/embedded/test/fixtures/html/index.html vendor/plugins/embedded/test/fixtures/html/misc/misc.html vendor/plugins/embedded/test/fixtures/html/misc/misc.txt vendor/plugins/embedded/test/functional/embedded_controller_test.rb vendor/plugins/embedded/test/test_helper.rb vendor/plugins/embedded/test/unit/embedded_test.rb
diffstat 20 files changed, 2605 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/COPYING	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/README	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,6 @@
+Embedded plugin for Redmine
+Copyright (C) 2008  Jean-Philippe Lang
+
+The plugin lets you embed html pages (eg. documentation, test reports) in your projects.
+
+See: http://www.redmine.org/wiki/redmine/PluginEmbedded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/RUNNING_TESTS	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,1 @@
+rake test:plugins PLUGIN=embedded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/app/controllers/embedded_controller.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,112 @@
+# Redmine - project management software
+# Copyright (C) 2008  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+require 'iconv'
+
+class EmbeddedController < ApplicationController
+  class EmbeddedControllerError < StandardError; end
+  
+  unloadable
+  layout 'base'
+  before_filter :find_project, :authorize
+  
+  def index
+    path = get_real_path(params[:path])
+    if File.directory?(path)
+      file = get_index_file(path)
+      target = params[:path] || []
+      target << file
+      # Forces redirect to the index file when the requested path is a directory
+      # so that relative links in embedded html pages work
+      redirect_to :path => target
+      return
+    end
+    
+    # Check file extension
+    raise EmbeddedControllerError.new('This file can not be viewed (invalid extension).') unless Redmine::Plugins::Embedded.valid_extension?(path)
+    
+    if Redmine::MimeType.is_type?('image', path)
+      send_file path, :disposition => 'inline', :type => Redmine::MimeType.of(path)
+    else
+      embed_file path
+    end
+    
+  rescue Errno::ENOENT => e
+    # File was not found
+    render_404
+  rescue Errno::EACCES => e
+    # Can not read the file
+    render_error "Unable to read the file: #{e.message}"
+  rescue EmbeddedControllerError => e
+    render_error e.message
+  end
+  
+  private
+  
+  def find_project
+    @project = Project.find(params[:id])
+  rescue ActiveRecord::RecordNotFound
+    render_404
+  end
+  
+  # Return the path to the html root directory for the current project
+  def get_project_directory
+    @project_directory ||= Setting.plugin_embedded['path'].to_s.gsub('{PROJECT}', @project.identifier)
+  end
+  
+  # Returns the absolute path of the requested file
+  # Parameter is an Array
+  def get_real_path(path)
+    real = get_project_directory
+    real = File.join(real, path) unless path.nil? || path.empty?
+    dir = File.expand_path(get_project_directory)
+    real = File.expand_path(real)
+    raise Errno::ENOENT unless real.starts_with?(dir) && File.exist?(real)
+    real
+  end
+  
+  # Returns the index file in the given directory
+  # and raises an exception if none is found
+  def get_index_file(dir)
+    indexes = Setting.plugin_embedded['index'].to_s.split
+    file = indexes.find {|f| File.exist?(File.join(dir, f))}
+    raise EmbeddedControllerError.new("No index file found in #{dir} (#{indexes.join(', ')}).") if file.nil?
+    file
+  end
+  
+  # Renders a given HTML file
+  def embed_file(path)
+    @content = File.read(path)
+    
+    # Extract html title from embedded page
+    if @content =~ %r{<title>([^<]*)</title>}mi
+      @title = $1.strip
+    end
+    
+    # Keep html body only
+    @content.gsub!(%r{^.*<body[^>]*>(.*)</body>.*$}mi, '\\1')
+    
+    # Re-encode content if needed
+    source_encoding = Setting.plugin_embedded['encoding'].to_s
+    unless source_encoding.blank?
+      begin; @content = Iconv.new('UTF-8', source_encoding).iconv(@content); rescue; end
+    end
+    
+    @doc_template = Redmine::Plugins::Embedded.detect_template_from_path(path)
+    render :action => 'index'
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/app/helpers/embedded_helper.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,35 @@
+# Redmine - project management software
+# Copyright (C) 2008  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+module EmbeddedHelper
+
+  # Adds include tags for assets of the given template
+  def asset_include_tags(template)
+  
+    Redmine::Plugins::Embedded.assets(template).each { |asset| content_for(:header_tags) { asset_include_tag(asset) } }
+  end
+  
+  private
+
+  def asset_include_tag(asset)
+    if asset =~ %r{\.js$}
+      javascript_include_tag(asset, :plugin => 'embedded')
+    else
+      stylesheet_link_tag(asset, :plugin => 'embedded')
+    end
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/app/views/embedded/index.rhtml	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,7 @@
+<!-- Embedded page -->
+<%= @content %>
+<!-- Embedded page end -->
+
+<% html_title(@title) if @title %>
+
+<% asset_include_tags(@doc_template) %>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/app/views/settings/_embedded.rhtml	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,22 @@
+<p><label>HTML directory</label>
+<%= text_field_tag 'settings[path]', @settings['path'], :size => 80 %>
+<br /><em>Use {PROJECT} to include the project identifier in the path</em></p>
+
+<p><label>Index files</label>
+<%= text_area_tag 'settings[index]', @settings['index'], :cols => 60, :rows => 3 %>
+<br /><em>Space separated list of index files by priority</em></p>
+
+<p><label>Valid extensions</label>
+<%= text_area_tag 'settings[extensions]', @settings['extensions'], :cols => 60, :rows => 3 %>
+<br /><em>Space separated list of file extensions that can be viewed (case insensitive)</em></p>
+
+<p><label>Default template</label>
+<%= select_tag 'settings[template]', options_for_select([''] + Redmine::Plugins::Embedded.available_templates, @settings['template']) %></p>
+
+<p><label>Files encoding</label>
+<%= text_field_tag 'settings[encoding]', @settings['encoding'] %>
+<br /><em>Eg. ISO-8859-1<br />Leave this field empty if HTML files are UTF-8 encoded</em></p>
+
+<p><label>Menu caption</label>
+<%= text_field_tag 'settings[menu]', @settings['menu'], :size => 30 %>
+<br /><em>Clear this field if you don't want to add a tab to the project menu</em></p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/assets/javascripts/rcov.js	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,18 @@
+function toggleCode( id ) {
+  if ( document.getElementById )
+    elem = document.getElementById( id );
+  else if ( document.all )
+    elem = eval( "document.all." + id );
+  else
+    return false;
+
+  elemStyle = elem.style;
+  
+  if ( elemStyle.display != "block" ) {
+    elemStyle.display = "block"
+  } else {
+    elemStyle.display = "none"
+  }
+
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/assets/stylesheets/doxygen.css	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,174 @@
+#content {
+	font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+#content h1, h2, h3 {border: 0;}
+#content h1 {margin-bottom: 1em;}
+#content CAPTION { font-weight: bold }
+#content DIV.qindex {
+	line-height: 120%;
+	margin-bottom: 1em;
+}
+#content A.qindex {
+   text-decoration: none;
+   font-weight: bold;
+   padding: 2px;
+}
+#content A.qindexHL {
+	text-decoration: underline;
+    font-weight: bold;
+	padding: 2px;
+}
+#content A.el { text-decoration: none; font-weight: bold }
+#content A.elRef { font-weight: bold }
+#content A.code { text-decoration: none; font-weight: normal; color: #1A419D}
+#content A.codeRef { font-weight: normal; color: #1A419D}
+#content DL.el { margin-left: -1cm }
+#content PRE.fragment {
+	border: 1px solid #CCCCCC;
+	background-color: #f5f5f5;
+	margin-top: 4px;
+	margin-bottom: 4px;
+	margin-left: 2px;
+	margin-right: 8px;
+	padding-left: 6px;
+	padding-right: 6px;
+	padding-top: 4px;
+	padding-bottom: 4px;
+}
+#content DIV.fragment {
+	border: 1px solid #CCCCCC;
+	background-color: #f5f5f5;
+	padding: 6px;
+}
+#content DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
+#content TD.md { background-color: #F4F4FB; font-weight: bold; }
+#content TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
+#content TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
+#content DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+	font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+#content DIV.groupText { margin-left: 16px; font-style: italic; font-size: 14px }
+#content TD.indexkey {
+	background-color: #eeeeff;
+	font-weight: bold;
+	padding-right  : 10px;
+	padding-top    : 2px;
+	padding-left   : 10px;
+	padding-bottom : 2px;
+	margin-left    : 0px;
+	margin-right   : 0px;
+	margin-top     : 2px;
+	margin-bottom  : 2px;
+	border: 1px solid #CCCCCC;
+}
+#content TD.indexvalue {
+	background-color: #eeeeff;
+	font-style: italic;
+	padding-right  : 10px;
+	padding-top    : 2px;
+	padding-left   : 10px;
+	padding-bottom : 2px;
+	margin-left    : 0px;
+	margin-right   : 0px;
+	margin-top     : 2px;
+	margin-bottom  : 2px;
+	border: 1px solid #CCCCCC;
+}
+#content TR.memlist {
+   background-color: #f0f0f0; 
+}
+#content P.formulaDsp { text-align: center; }
+#content IMG.formulaDsp { }
+#content IMG.formulaInl { vertical-align: middle; }
+#content SPAN.keyword       { color: #008000 }
+#content SPAN.keywordtype   { color: #604020 }
+#content SPAN.keywordflow   { color: #e08000 }
+#content SPAN.comment       { color: #800000 }
+#content SPAN.preprocessor  { color: #806020 }
+#content SPAN.stringliteral { color: #002080 }
+#content SPAN.charliteral   { color: #008080 }
+#content .mdTable {
+	border: 1px solid #868686;
+	background-color: #F4F4FB;
+}
+#content .mdRow {
+	padding: 8px 10px;
+}
+#content .mdescLeft {
+       padding: 0px 8px 4px 8px;
+	font-size: 14px;
+	font-style: italic;
+	background-color: #FAFAFA;
+	border-top: 1px none #E0E0E0;
+	border-right: 1px none #E0E0E0;
+	border-bottom: 1px none #E0E0E0;
+	border-left: 1px none #E0E0E0;
+	margin: 0px;
+}
+#content .mdescRight {
+       padding: 0px 8px 4px 8px;
+	font-size: 14px;
+	font-style: italic;
+	background-color: #FAFAFA;
+	border-top: 1px none #E0E0E0;
+	border-right: 1px none #E0E0E0;
+	border-bottom: 1px none #E0E0E0;
+	border-left: 1px none #E0E0E0;
+	margin: 0px;
+}
+#content .memItemLeft {
+	padding: 1px 0px 0px 8px;
+	margin: 4px;
+	border-top-width: 1px;
+	border-right-width: 1px;
+	border-bottom-width: 1px;
+	border-left-width: 1px;
+	border-top-style: solid;
+	border-top-color: #E0E0E0;
+	border-right-color: #E0E0E0;
+	border-bottom-color: #E0E0E0;
+	border-left-color: #E0E0E0;
+	border-right-style: none;
+	border-bottom-style: none;
+	border-left-style: none;
+	background-color: #FAFAFA;
+	font-family: Geneva, Arial, Helvetica, sans-serif;
+	font-size: 12px;
+}
+#content .memItemRight {
+	padding: 1px 8px 0px 8px;
+	margin: 4px;
+	border-top-width: 1px;
+	border-right-width: 1px;
+	border-bottom-width: 1px;
+	border-left-width: 1px;
+	border-top-style: solid;
+	border-top-color: #E0E0E0;
+	border-right-color: #E0E0E0;
+	border-bottom-color: #E0E0E0;
+	border-left-color: #E0E0E0;
+	border-right-style: none;
+	border-bottom-style: none;
+	border-left-style: none;
+	background-color: #FAFAFA;
+	font-family: Geneva, Arial, Helvetica, sans-serif;
+	font-size: 13px;
+}
+#content .search     { color: #003399;
+              font-weight: bold;
+}
+#content FORM.search {
+              margin-bottom: 0px;
+              margin-top: 0px;
+}
+#content INPUT.search { font-size: 75%;
+               color: #000080;
+               font-weight: normal;
+               background-color: #eeeeff;
+}
+#content TD.tiny      { font-size: 75%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/assets/stylesheets/javadoc.css	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,23 @@
+/* Javadoc style sheet */
+
+/* Table colors */
+.TableHeadingColor     { background: #eef; } /* Dark mauve */
+.TableHeadingColor th b { font-size: 70%; }
+.TableSubHeadingColor  { background: #EEEEee;  } /* Light mauve */
+.TableRowColor         { background: #FFFFFF;  } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont   { font-size: 100%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+.FrameHeadingFont { font-size:  90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+.FrameItemFont    { font-size:  90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+
+/* Navigation bar fonts and colors */
+.NavBarCell1    { background-color: inherit; } /* Light mauve */
+.NavBarCell1Rev { background-color: inherit; } /* Dark Blue */
+.NavBarFont1    { font-family: Arial, Helvetica, sans-serif;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; font-style: underline; }
+
+.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000; display: none;}
+.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000}
+
+#content table { border-collapse: collapse; border-color: #ddd; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/assets/stylesheets/rcov.css	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,525 @@
+span.cross-ref-title {
+ font-size: 140%;
+}
+span.cross-ref a {
+ text-decoration: none;
+}
+span.cross-ref {
+ background-color:#f3f7fa;
+ border: 1px dashed #333;
+ margin: 1em;
+ padding: 0.5em;
+ overflow: hidden;
+}
+a.crossref-toggle {
+ text-decoration: none;
+}
+span.marked0 {
+ background-color: rgb(185, 210, 200);
+ display: block;
+}
+span.marked1 {
+ background-color: rgb(190, 215, 205);
+ display: block;
+}
+span.inferred0 {
+ background-color: rgb(175, 200, 200);
+ display: block;
+}
+span.inferred1 {
+ background-color: rgb(180, 205, 205);
+ display: block;
+}
+span.uncovered0 {
+ background-color: rgb(225, 110, 110);
+ display: block;
+}
+span.uncovered1 {
+ background-color: rgb(235, 120, 120);
+ display: block;
+}
+span.overview {
+ border-bottom: 8px solid black;
+}
+div.overview {
+ border-bottom: 8px solid black;
+}
+#content div.footer {
+ font-size: 68%;
+ margin-top: 1.5em;
+}
+#content h1, h2, h3, h4, h5, h6 {
+ margin-bottom: 0.5em;
+}
+h5 {
+ margin-top: 0.5em;
+}
+.hidden {
+ display: none;
+}
+div.separator {
+ height: 10px;
+}
+/* Commented out for better readability, esp. on IE */
+/*
+table tr td, table tr th {
+ font-size: 68%;
+}
+td.value table tr td {
+ font-size: 11px;
+}
+*/
+table.percent_graph {
+ height: 12px;
+ border: #808080 1px solid;
+ empty-cells: show;
+}
+table.percent_graph td.covered {
+ height: 10px;
+ background: #00f000;
+}
+table.percent_graph td.uncovered {
+ height: 10px;
+ background: #e00000;
+}
+table.percent_graph td.NA {
+ height: 10px;
+ background: #eaeaea;
+}
+table.report {
+ border-collapse: collapse;
+ width: 100%;
+}
+table.report td.heading {
+ background: #dcecff;
+ border: #d0d0d0 1px solid;
+ font-weight: bold;
+ text-align: center;
+}
+table.report td.heading:hover {
+ background: #c0ffc0;
+}
+table.report td.text {
+ border: #d0d0d0 1px solid;
+}
+table.report td.value,
+table.report td.lines_total,
+table.report td.lines_code {
+ text-align: right;
+ border: #d0d0d0 1px solid;
+}
+table.report tr.light {
+ background-color: #f6f7f8;
+}
+table.report tr.dark {
+ background-color: #fff;
+}
+span.run0 {
+  background-color: rgb(178, 204, 255);
+  display: block;
+}
+span.run1 {
+  background-color: rgb(178, 206, 255);
+  display: block;
+}
+span.run2 {
+  background-color: rgb(178, 209, 255);
+  display: block;
+}
+span.run3 {
+  background-color: rgb(178, 211, 255);
+  display: block;
+}
+span.run4 {
+  background-color: rgb(178, 214, 255);
+  display: block;
+}
+span.run5 {
+  background-color: rgb(178, 218, 255);
+  display: block;
+}
+span.run6 {
+  background-color: rgb(178, 220, 255);
+  display: block;
+}
+span.run7 {
+  background-color: rgb(178, 223, 255);
+  display: block;
+}
+span.run8 {
+  background-color: rgb(178, 225, 255);
+  display: block;
+}
+span.run9 {
+  background-color: rgb(178, 228, 255);
+  display: block;
+}
+span.run10 {
+  background-color: rgb(178, 232, 255);
+  display: block;
+}
+span.run11 {
+  background-color: rgb(178, 234, 255);
+  display: block;
+}
+span.run12 {
+  background-color: rgb(178, 237, 255);
+  display: block;
+}
+span.run13 {
+  background-color: rgb(178, 239, 255);
+  display: block;
+}
+span.run14 {
+  background-color: rgb(178, 242, 255);
+  display: block;
+}
+span.run15 {
+  background-color: rgb(178, 246, 255);
+  display: block;
+}
+span.run16 {
+  background-color: rgb(178, 248, 255);
+  display: block;
+}
+span.run17 {
+  background-color: rgb(178, 251, 255);
+  display: block;
+}
+span.run18 {
+  background-color: rgb(178, 253, 255);
+  display: block;
+}
+span.run19 {
+  background-color: rgb(178, 255, 253);
+  display: block;
+}
+span.run20 {
+  background-color: rgb(178, 255, 249);
+  display: block;
+}
+span.run21 {
+  background-color: rgb(178, 255, 247);
+  display: block;
+}
+span.run22 {
+  background-color: rgb(178, 255, 244);
+  display: block;
+}
+span.run23 {
+  background-color: rgb(178, 255, 242);
+  display: block;
+}
+span.run24 {
+  background-color: rgb(178, 255, 239);
+  display: block;
+}
+span.run25 {
+  background-color: rgb(178, 255, 235);
+  display: block;
+}
+span.run26 {
+  background-color: rgb(178, 255, 233);
+  display: block;
+}
+span.run27 {
+  background-color: rgb(178, 255, 230);
+  display: block;
+}
+span.run28 {
+  background-color: rgb(178, 255, 228);
+  display: block;
+}
+span.run29 {
+  background-color: rgb(178, 255, 225);
+  display: block;
+}
+span.run30 {
+  background-color: rgb(178, 255, 221);
+  display: block;
+}
+span.run31 {
+  background-color: rgb(178, 255, 219);
+  display: block;
+}
+span.run32 {
+  background-color: rgb(178, 255, 216);
+  display: block;
+}
+span.run33 {
+  background-color: rgb(178, 255, 214);
+  display: block;
+}
+span.run34 {
+  background-color: rgb(178, 255, 211);
+  display: block;
+}
+span.run35 {
+  background-color: rgb(178, 255, 207);
+  display: block;
+}
+span.run36 {
+  background-color: rgb(178, 255, 205);
+  display: block;
+}
+span.run37 {
+  background-color: rgb(178, 255, 202);
+  display: block;
+}
+span.run38 {
+  background-color: rgb(178, 255, 200);
+  display: block;
+}
+span.run39 {
+  background-color: rgb(178, 255, 197);
+  display: block;
+}
+span.run40 {
+  background-color: rgb(178, 255, 193);
+  display: block;
+}
+span.run41 {
+  background-color: rgb(178, 255, 191);
+  display: block;
+}
+span.run42 {
+  background-color: rgb(178, 255, 188);
+  display: block;
+}
+span.run43 {
+  background-color: rgb(178, 255, 186);
+  display: block;
+}
+span.run44 {
+  background-color: rgb(178, 255, 183);
+  display: block;
+}
+span.run45 {
+  background-color: rgb(178, 255, 179);
+  display: block;
+}
+span.run46 {
+  background-color: rgb(179, 255, 178);
+  display: block;
+}
+span.run47 {
+  background-color: rgb(182, 255, 178);
+  display: block;
+}
+span.run48 {
+  background-color: rgb(184, 255, 178);
+  display: block;
+}
+span.run49 {
+  background-color: rgb(187, 255, 178);
+  display: block;
+}
+span.run50 {
+  background-color: rgb(191, 255, 178);
+  display: block;
+}
+span.run51 {
+  background-color: rgb(193, 255, 178);
+  display: block;
+}
+span.run52 {
+  background-color: rgb(196, 255, 178);
+  display: block;
+}
+span.run53 {
+  background-color: rgb(198, 255, 178);
+  display: block;
+}
+span.run54 {
+  background-color: rgb(201, 255, 178);
+  display: block;
+}
+span.run55 {
+  background-color: rgb(205, 255, 178);
+  display: block;
+}
+span.run56 {
+  background-color: rgb(207, 255, 178);
+  display: block;
+}
+span.run57 {
+  background-color: rgb(210, 255, 178);
+  display: block;
+}
+span.run58 {
+  background-color: rgb(212, 255, 178);
+  display: block;
+}
+span.run59 {
+  background-color: rgb(215, 255, 178);
+  display: block;
+}
+span.run60 {
+  background-color: rgb(219, 255, 178);
+  display: block;
+}
+span.run61 {
+  background-color: rgb(221, 255, 178);
+  display: block;
+}
+span.run62 {
+  background-color: rgb(224, 255, 178);
+  display: block;
+}
+span.run63 {
+  background-color: rgb(226, 255, 178);
+  display: block;
+}
+span.run64 {
+  background-color: rgb(229, 255, 178);
+  display: block;
+}
+span.run65 {
+  background-color: rgb(233, 255, 178);
+  display: block;
+}
+span.run66 {
+  background-color: rgb(235, 255, 178);
+  display: block;
+}
+span.run67 {
+  background-color: rgb(238, 255, 178);
+  display: block;
+}
+span.run68 {
+  background-color: rgb(240, 255, 178);
+  display: block;
+}
+span.run69 {
+  background-color: rgb(243, 255, 178);
+  display: block;
+}
+span.run70 {
+  background-color: rgb(247, 255, 178);
+  display: block;
+}
+span.run71 {
+  background-color: rgb(249, 255, 178);
+  display: block;
+}
+span.run72 {
+  background-color: rgb(252, 255, 178);
+  display: block;
+}
+span.run73 {
+  background-color: rgb(255, 255, 178);
+  display: block;
+}
+span.run74 {
+  background-color: rgb(255, 252, 178);
+  display: block;
+}
+span.run75 {
+  background-color: rgb(255, 248, 178);
+  display: block;
+}
+span.run76 {
+  background-color: rgb(255, 246, 178);
+  display: block;
+}
+span.run77 {
+  background-color: rgb(255, 243, 178);
+  display: block;
+}
+span.run78 {
+  background-color: rgb(255, 240, 178);
+  display: block;
+}
+span.run79 {
+  background-color: rgb(255, 238, 178);
+  display: block;
+}
+span.run80 {
+  background-color: rgb(255, 234, 178);
+  display: block;
+}
+span.run81 {
+  background-color: rgb(255, 232, 178);
+  display: block;
+}
+span.run82 {
+  background-color: rgb(255, 229, 178);
+  display: block;
+}
+span.run83 {
+  background-color: rgb(255, 226, 178);
+  display: block;
+}
+span.run84 {
+  background-color: rgb(255, 224, 178);
+  display: block;
+}
+span.run85 {
+  background-color: rgb(255, 220, 178);
+  display: block;
+}
+span.run86 {
+  background-color: rgb(255, 218, 178);
+  display: block;
+}
+span.run87 {
+  background-color: rgb(255, 215, 178);
+  display: block;
+}
+span.run88 {
+  background-color: rgb(255, 212, 178);
+  display: block;
+}
+span.run89 {
+  background-color: rgb(255, 210, 178);
+  display: block;
+}
+span.run90 {
+  background-color: rgb(255, 206, 178);
+  display: block;
+}
+span.run91 {
+  background-color: rgb(255, 204, 178);
+  display: block;
+}
+span.run92 {
+  background-color: rgb(255, 201, 178);
+  display: block;
+}
+span.run93 {
+  background-color: rgb(255, 198, 178);
+  display: block;
+}
+span.run94 {
+  background-color: rgb(255, 196, 178);
+  display: block;
+}
+span.run95 {
+  background-color: rgb(255, 192, 178);
+  display: block;
+}
+span.run96 {
+  background-color: rgb(255, 189, 178);
+  display: block;
+}
+span.run97 {
+  background-color: rgb(255, 187, 178);
+  display: block;
+}
+span.run98 {
+  background-color: rgb(255, 184, 178);
+  display: block;
+}
+span.run99 {
+  background-color: rgb(255, 182, 178);
+  display: block;
+}
+span.run100 {
+  background-color: rgb(255, 178, 178);
+  display: block;
+}
+pre {
+    white-space: pre-wrap; /* CSS2.1 compliant */
+    white-space: -moz-pre-wrap; /* Mozilla-based browsers */
+    white-space: -o-pre-wrap; /* Opera 7+ */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/init.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,33 @@
+require 'redmine'
+require 'embedded'
+
+Redmine::Plugin.register :embedded do
+  name 'Embedded'
+  author 'Jean-Philippe Lang'
+  description 'Embed various documentations in your projects'
+  version '0.0.1'
+  settings :default => { 'path' => '/var/doc/{PROJECT}/html',
+                         'index' => 'main.html overview-summary.html index.html',
+                         'extensions' => 'html png gif',
+                         'template' => '',
+                         'encoding' => '',
+                         'menu' => 'Embedded' },
+           :partial => 'settings/embedded'
+
+  project_module :embedded do
+    permission :view_embedded_doc, {:embedded => :index}
+  end
+
+  menu :project_menu, :embedded, { :controller => 'embedded', :action => 'index', :path => nil },
+                                 :caption => Proc.new { Setting.plugin_embedded['menu'] },
+                                 :if => Proc.new { !Setting.plugin_embedded['menu'].blank? }
+end
+
+# Routes
+class << ActionController::Routing::Routes;self;end.class_eval do
+  define_method :clear!, lambda {}
+end
+
+ActionController::Routing::Routes.draw do |map|
+  map.connect 'embedded/:id/*path', :controller => 'embedded', :action => 'index'
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/lib/embedded.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,64 @@
+# Redmine - project management software
+# Copyright (C) 2008  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+module Redmine
+  module Plugins
+    module Embedded
+      class << self
+        
+        # Returns an Array of available templates
+        def available_templates
+          assets_by_template.keys.sort
+        end
+        
+        # Returns the assets for a given template
+        def assets(template)
+          assets_by_template.has_key?(template) ? assets_by_template[template] : []
+        end
+        
+        def detect_template_from_path(path)
+          t = path.to_s.split(%r{[/\\]}) & available_templates
+          t.empty? ? Setting.plugin_embedded['template'].to_s : t.first
+        end
+        
+        def valid_extension?(path)
+          extensions = Setting.plugin_embedded['extensions'].to_s.split.each(&:downcase)
+          extensions.include?(File.extname(path).downcase[1..-1])
+        end
+
+        private
+        
+        # A Hash of available assets by template
+        def assets_by_template
+          @@assets_by_template ||= scan_assets
+        end
+        
+        # Scans assets directory for templates
+        # and returns a Hash of available assets by template
+        def scan_assets
+          a = Hash.new {|h,k| h[k] = [] }
+          Dir.glob(File.join(File.dirname(__FILE__), '../assets/*/*.{css,js}')).each do |asset|
+            asset = File.basename(asset)
+            template = asset.gsub(%r{\.(js|css)$}, '')
+            a[template] << asset
+          end
+          a
+        end
+      end
+    end
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/fixtures/html/app-controllers-account_controller_rb.html	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,783 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'><head><title>app/controllers/account_controller.rb - C0 code coverage information</title>
+    <style type='text/css'>body { background-color: rgb(240, 240, 245); }</style>
+    <style type='text/css'>span.cross-ref-title {
+ font-size: 140%;
+}
+span.cross-ref a {
+ text-decoration: none;
+}
+span.cross-ref {
+ background-color:#f3f7fa;
+ border: 1px dashed #333;
+ margin: 1em;
+ padding: 0.5em;
+ overflow: hidden;
+}
+a.crossref-toggle {
+ text-decoration: none;
+}
+span.marked0 {
+ background-color: rgb(185, 210, 200);
+ display: block;
+}
+span.marked1 {
+ background-color: rgb(190, 215, 205);
+ display: block;
+}
+span.inferred0 {
+ background-color: rgb(175, 200, 200);
+ display: block;
+}
+span.inferred1 {
+ background-color: rgb(180, 205, 205);
+ display: block;
+}
+span.uncovered0 {
+ background-color: rgb(225, 110, 110);
+ display: block;
+}
+span.uncovered1 {
+ background-color: rgb(235, 120, 120);
+ display: block;
+}
+span.overview {
+ border-bottom: 8px solid black;
+}
+div.overview {
+ border-bottom: 8px solid black;
+}
+body {
+ font-family: verdana, arial, helvetica;
+}
+div.footer {
+ font-size: 68%;
+ margin-top: 1.5em;
+}
+h1, h2, h3, h4, h5, h6 {
+ margin-bottom: 0.5em;
+}
+h5 {
+ margin-top: 0.5em;
+}
+.hidden {
+ display: none;
+}
+div.separator {
+ height: 10px;
+}
+/* Commented out for better readability, esp. on IE */
+/*
+table tr td, table tr th {
+ font-size: 68%;
+}
+td.value table tr td {
+ font-size: 11px;
+}
+*/
+table.percent_graph {
+ height: 12px;
+ border: #808080 1px solid;
+ empty-cells: show;
+}
+table.percent_graph td.covered {
+ height: 10px;
+ background: #00f000;
+}
+table.percent_graph td.uncovered {
+ height: 10px;
+ background: #e00000;
+}
+table.percent_graph td.NA {
+ height: 10px;
+ background: #eaeaea;
+}
+table.report {
+ border-collapse: collapse;
+ width: 100%;
+}
+table.report td.heading {
+ background: #dcecff;
+ border: #d0d0d0 1px solid;
+ font-weight: bold;
+ text-align: center;
+}
+table.report td.heading:hover {
+ background: #c0ffc0;
+}
+table.report td.text {
+ border: #d0d0d0 1px solid;
+}
+table.report td.value,
+table.report td.lines_total,
+table.report td.lines_code {
+ text-align: right;
+ border: #d0d0d0 1px solid;
+}
+table.report tr.light {
+ background-color: rgb(240, 240, 245);
+}
+table.report tr.dark {
+ background-color: rgb(230, 230, 235);
+}
+</style>
+    <script type='text/javascript'>
+// <![CDATA[
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+    
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+  
+  // Make cross-references hidden by default
+  document.writeln( "<style type=\"text/css\">span.cross-ref { display: none }</style>" )
+  // ]]>
+</script>
+    <style type='text/css'>span.run0 {
+  background-color: rgb(178, 204, 255);
+  display: block;
+}
+span.run1 {
+  background-color: rgb(178, 206, 255);
+  display: block;
+}
+span.run2 {
+  background-color: rgb(178, 209, 255);
+  display: block;
+}
+span.run3 {
+  background-color: rgb(178, 211, 255);
+  display: block;
+}
+span.run4 {
+  background-color: rgb(178, 214, 255);
+  display: block;
+}
+span.run5 {
+  background-color: rgb(178, 218, 255);
+  display: block;
+}
+span.run6 {
+  background-color: rgb(178, 220, 255);
+  display: block;
+}
+span.run7 {
+  background-color: rgb(178, 223, 255);
+  display: block;
+}
+span.run8 {
+  background-color: rgb(178, 225, 255);
+  display: block;
+}
+span.run9 {
+  background-color: rgb(178, 228, 255);
+  display: block;
+}
+span.run10 {
+  background-color: rgb(178, 232, 255);
+  display: block;
+}
+span.run11 {
+  background-color: rgb(178, 234, 255);
+  display: block;
+}
+span.run12 {
+  background-color: rgb(178, 237, 255);
+  display: block;
+}
+span.run13 {
+  background-color: rgb(178, 239, 255);
+  display: block;
+}
+span.run14 {
+  background-color: rgb(178, 242, 255);
+  display: block;
+}
+span.run15 {
+  background-color: rgb(178, 246, 255);
+  display: block;
+}
+span.run16 {
+  background-color: rgb(178, 248, 255);
+  display: block;
+}
+span.run17 {
+  background-color: rgb(178, 251, 255);
+  display: block;
+}
+span.run18 {
+  background-color: rgb(178, 253, 255);
+  display: block;
+}
+span.run19 {
+  background-color: rgb(178, 255, 253);
+  display: block;
+}
+span.run20 {
+  background-color: rgb(178, 255, 249);
+  display: block;
+}
+span.run21 {
+  background-color: rgb(178, 255, 247);
+  display: block;
+}
+span.run22 {
+  background-color: rgb(178, 255, 244);
+  display: block;
+}
+span.run23 {
+  background-color: rgb(178, 255, 242);
+  display: block;
+}
+span.run24 {
+  background-color: rgb(178, 255, 239);
+  display: block;
+}
+span.run25 {
+  background-color: rgb(178, 255, 235);
+  display: block;
+}
+span.run26 {
+  background-color: rgb(178, 255, 233);
+  display: block;
+}
+span.run27 {
+  background-color: rgb(178, 255, 230);
+  display: block;
+}
+span.run28 {
+  background-color: rgb(178, 255, 228);
+  display: block;
+}
+span.run29 {
+  background-color: rgb(178, 255, 225);
+  display: block;
+}
+span.run30 {
+  background-color: rgb(178, 255, 221);
+  display: block;
+}
+span.run31 {
+  background-color: rgb(178, 255, 219);
+  display: block;
+}
+span.run32 {
+  background-color: rgb(178, 255, 216);
+  display: block;
+}
+span.run33 {
+  background-color: rgb(178, 255, 214);
+  display: block;
+}
+span.run34 {
+  background-color: rgb(178, 255, 211);
+  display: block;
+}
+span.run35 {
+  background-color: rgb(178, 255, 207);
+  display: block;
+}
+span.run36 {
+  background-color: rgb(178, 255, 205);
+  display: block;
+}
+span.run37 {
+  background-color: rgb(178, 255, 202);
+  display: block;
+}
+span.run38 {
+  background-color: rgb(178, 255, 200);
+  display: block;
+}
+span.run39 {
+  background-color: rgb(178, 255, 197);
+  display: block;
+}
+span.run40 {
+  background-color: rgb(178, 255, 193);
+  display: block;
+}
+span.run41 {
+  background-color: rgb(178, 255, 191);
+  display: block;
+}
+span.run42 {
+  background-color: rgb(178, 255, 188);
+  display: block;
+}
+span.run43 {
+  background-color: rgb(178, 255, 186);
+  display: block;
+}
+span.run44 {
+  background-color: rgb(178, 255, 183);
+  display: block;
+}
+span.run45 {
+  background-color: rgb(178, 255, 179);
+  display: block;
+}
+span.run46 {
+  background-color: rgb(179, 255, 178);
+  display: block;
+}
+span.run47 {
+  background-color: rgb(182, 255, 178);
+  display: block;
+}
+span.run48 {
+  background-color: rgb(184, 255, 178);
+  display: block;
+}
+span.run49 {
+  background-color: rgb(187, 255, 178);
+  display: block;
+}
+span.run50 {
+  background-color: rgb(191, 255, 178);
+  display: block;
+}
+span.run51 {
+  background-color: rgb(193, 255, 178);
+  display: block;
+}
+span.run52 {
+  background-color: rgb(196, 255, 178);
+  display: block;
+}
+span.run53 {
+  background-color: rgb(198, 255, 178);
+  display: block;
+}
+span.run54 {
+  background-color: rgb(201, 255, 178);
+  display: block;
+}
+span.run55 {
+  background-color: rgb(205, 255, 178);
+  display: block;
+}
+span.run56 {
+  background-color: rgb(207, 255, 178);
+  display: block;
+}
+span.run57 {
+  background-color: rgb(210, 255, 178);
+  display: block;
+}
+span.run58 {
+  background-color: rgb(212, 255, 178);
+  display: block;
+}
+span.run59 {
+  background-color: rgb(215, 255, 178);
+  display: block;
+}
+span.run60 {
+  background-color: rgb(219, 255, 178);
+  display: block;
+}
+span.run61 {
+  background-color: rgb(221, 255, 178);
+  display: block;
+}
+span.run62 {
+  background-color: rgb(224, 255, 178);
+  display: block;
+}
+span.run63 {
+  background-color: rgb(226, 255, 178);
+  display: block;
+}
+span.run64 {
+  background-color: rgb(229, 255, 178);
+  display: block;
+}
+span.run65 {
+  background-color: rgb(233, 255, 178);
+  display: block;
+}
+span.run66 {
+  background-color: rgb(235, 255, 178);
+  display: block;
+}
+span.run67 {
+  background-color: rgb(238, 255, 178);
+  display: block;
+}
+span.run68 {
+  background-color: rgb(240, 255, 178);
+  display: block;
+}
+span.run69 {
+  background-color: rgb(243, 255, 178);
+  display: block;
+}
+span.run70 {
+  background-color: rgb(247, 255, 178);
+  display: block;
+}
+span.run71 {
+  background-color: rgb(249, 255, 178);
+  display: block;
+}
+span.run72 {
+  background-color: rgb(252, 255, 178);
+  display: block;
+}
+span.run73 {
+  background-color: rgb(255, 255, 178);
+  display: block;
+}
+span.run74 {
+  background-color: rgb(255, 252, 178);
+  display: block;
+}
+span.run75 {
+  background-color: rgb(255, 248, 178);
+  display: block;
+}
+span.run76 {
+  background-color: rgb(255, 246, 178);
+  display: block;
+}
+span.run77 {
+  background-color: rgb(255, 243, 178);
+  display: block;
+}
+span.run78 {
+  background-color: rgb(255, 240, 178);
+  display: block;
+}
+span.run79 {
+  background-color: rgb(255, 238, 178);
+  display: block;
+}
+span.run80 {
+  background-color: rgb(255, 234, 178);
+  display: block;
+}
+span.run81 {
+  background-color: rgb(255, 232, 178);
+  display: block;
+}
+span.run82 {
+  background-color: rgb(255, 229, 178);
+  display: block;
+}
+span.run83 {
+  background-color: rgb(255, 226, 178);
+  display: block;
+}
+span.run84 {
+  background-color: rgb(255, 224, 178);
+  display: block;
+}
+span.run85 {
+  background-color: rgb(255, 220, 178);
+  display: block;
+}
+span.run86 {
+  background-color: rgb(255, 218, 178);
+  display: block;
+}
+span.run87 {
+  background-color: rgb(255, 215, 178);
+  display: block;
+}
+span.run88 {
+  background-color: rgb(255, 212, 178);
+  display: block;
+}
+span.run89 {
+  background-color: rgb(255, 210, 178);
+  display: block;
+}
+span.run90 {
+  background-color: rgb(255, 206, 178);
+  display: block;
+}
+span.run91 {
+  background-color: rgb(255, 204, 178);
+  display: block;
+}
+span.run92 {
+  background-color: rgb(255, 201, 178);
+  display: block;
+}
+span.run93 {
+  background-color: rgb(255, 198, 178);
+  display: block;
+}
+span.run94 {
+  background-color: rgb(255, 196, 178);
+  display: block;
+}
+span.run95 {
+  background-color: rgb(255, 192, 178);
+  display: block;
+}
+span.run96 {
+  background-color: rgb(255, 189, 178);
+  display: block;
+}
+span.run97 {
+  background-color: rgb(255, 187, 178);
+  display: block;
+}
+span.run98 {
+  background-color: rgb(255, 184, 178);
+  display: block;
+}
+span.run99 {
+  background-color: rgb(255, 182, 178);
+  display: block;
+}
+span.run100 {
+  background-color: rgb(255, 178, 178);
+  display: block;
+}
+</style>
+    </head>
+  <body><h3>C0 code coverage information</h3>
+    <p>Generated on Tue Jun 24 21:43:53 +0200 2008 with <a href='http://eigenclass.org/hiki/rcov'>rcov 0.8.1.2</a>
+      </p>
+    <hr/>
+    <pre><span class='marked0'>Code reported as executed by Ruby looks like this...
+</span><span class='marked1'>and this: this line is also marked as covered.
+</span><span class='inferred0'>Lines considered as run by rcov, but not reported by Ruby, look like this,
+</span><span class='inferred1'>and this: these lines were inferred by rcov (using simple heuristics).
+</span><span class='uncovered0'>Finally, here&apos;s a line marked as not executed.
+</span></pre>                       
+<table class='report'><thead><tr><td class='heading'>Name</td>
+      <td class='heading'>Total lines</td>
+      <td class='heading'>Lines of code</td>
+      <td class='heading'>Total coverage</td>
+      <td class='heading'>Code coverage</td>
+      </tr>
+    </thead>
+  <tbody><tr class='light'><td><a href='app-controllers-account_controller_rb.html'>app/controllers/account_controller.rb</a>
+        </td>
+      <td class='lines_total'><tt>173</tt>
+        </td>
+      <td class='lines_code'><tt>129</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>98.8%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='99'/>
+                  <td class='uncovered' width='1'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>98.4%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='98'/>
+                  <td class='uncovered' width='2'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+<pre><span class="inferred0"><a name="line1"></a>  1 # redMine - project management software
+</span><span class="inferred1"><a name="line2"></a>  2 # Copyright (C) 2006-2007  Jean-Philippe Lang
+</span><span class="inferred0"><a name="line3"></a>  3 #
+</span><span class="inferred1"><a name="line4"></a>  4 # This program is free software; you can redistribute it and/or
+</span><span class="inferred0"><a name="line5"></a>  5 # modify it under the terms of the GNU General Public License
+</span><span class="inferred1"><a name="line6"></a>  6 # as published by the Free Software Foundation; either version 2
+</span><span class="inferred0"><a name="line7"></a>  7 # of the License, or (at your option) any later version.
+</span><span class="inferred1"><a name="line8"></a>  8 # 
+</span><span class="inferred0"><a name="line9"></a>  9 # This program is distributed in the hope that it will be useful,
+</span><span class="inferred1"><a name="line10"></a> 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
+</span><span class="inferred0"><a name="line11"></a> 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+</span><span class="inferred1"><a name="line12"></a> 12 # GNU General Public License for more details.
+</span><span class="inferred0"><a name="line13"></a> 13 # 
+</span><span class="inferred1"><a name="line14"></a> 14 # You should have received a copy of the GNU General Public License
+</span><span class="inferred0"><a name="line15"></a> 15 # along with this program; if not, write to the Free Software
+</span><span class="inferred1"><a name="line16"></a> 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+</span><span class="inferred0"><a name="line17"></a> 17 
+</span><span class="marked1"><a name="line18"></a> 18 class AccountController &lt; ApplicationController
+</span><span class="marked0"><a name="line19"></a> 19   layout 'base'	
+</span><span class="marked1"><a name="line20"></a> 20   helper :custom_fields
+</span><span class="marked0"><a name="line21"></a> 21   include CustomFieldsHelper   
+</span><span class="inferred1"><a name="line22"></a> 22   
+</span><span class="inferred0"><a name="line23"></a> 23   # prevents login action to be filtered by check_if_login_required application scope filter
+</span><span class="marked1"><a name="line24"></a> 24   skip_before_filter :check_if_login_required, :only =&gt; [:login, :lost_password, :register, :activate]
+</span><span class="inferred0"><a name="line25"></a> 25 
+</span><span class="inferred1"><a name="line26"></a> 26   # Show user's account
+</span><span class="marked0"><a name="line27"></a> 27   def show
+</span><span class="marked1"><a name="line28"></a> 28     @user = User.find_active(params[:id])
+</span><span class="marked0"><a name="line29"></a> 29     @custom_values = @user.custom_values.find(:all, :include =&gt; :custom_field)
+</span><span class="inferred1"><a name="line30"></a> 30     
+</span><span class="inferred0"><a name="line31"></a> 31     # show only public projects and private projects that the logged in user is also a member of
+</span><span class="marked1"><a name="line32"></a> 32     @memberships = @user.memberships.select do |membership|
+</span><span class="marked0"><a name="line33"></a> 33       membership.project.is_public? || (User.current.member_of?(membership.project))
+</span><span class="inferred1"><a name="line34"></a> 34     end
+</span><span class="inferred0"><a name="line35"></a> 35   rescue ActiveRecord::RecordNotFound
+</span><span class="marked1"><a name="line36"></a> 36     render_404
+</span><span class="marked0"><a name="line37"></a> 37   end
+</span><span class="inferred1"><a name="line38"></a> 38 
+</span><span class="inferred0"><a name="line39"></a> 39   # Login request and validation
+</span><span class="marked1"><a name="line40"></a> 40   def login
+</span><span class="marked0"><a name="line41"></a> 41     if request.get?
+</span><span class="inferred1"><a name="line42"></a> 42       # Logout user
+</span><span class="marked0"><a name="line43"></a> 43       self.logged_user = nil
+</span><span class="inferred1"><a name="line44"></a> 44     else
+</span><span class="inferred0"><a name="line45"></a> 45       # Authenticate user
+</span><span class="marked1"><a name="line46"></a> 46       user = User.try_to_login(params[:username], params[:password])
+</span><span class="marked0"><a name="line47"></a> 47       if user
+</span><span class="marked1"><a name="line48"></a> 48         self.logged_user = user
+</span><span class="inferred0"><a name="line49"></a> 49         # generate a key and set cookie if autologin
+</span><span class="marked1"><a name="line50"></a> 50         if params[:autologin] &amp;&amp; Setting.autologin?
+</span><span class="marked0"><a name="line51"></a> 51           token = Token.create(:user =&gt; user, :action =&gt; 'autologin')
+</span><span class="marked1"><a name="line52"></a> 52           cookies[:autologin] = { :value =&gt; token.value, :expires =&gt; 1.year.from_now }
+</span><span class="inferred0"><a name="line53"></a> 53         end
+</span><span class="marked1"><a name="line54"></a> 54         redirect_back_or_default :controller =&gt; 'my', :action =&gt; 'page'
+</span><span class="inferred0"><a name="line55"></a> 55       else
+</span><span class="marked1"><a name="line56"></a> 56         flash.now[:error] = l(:notice_account_invalid_creditentials)
+</span><span class="inferred0"><a name="line57"></a> 57       end
+</span><span class="inferred1"><a name="line58"></a> 58     end
+</span><span class="uncovered0"><a name="line59"></a> 59   rescue User::OnTheFlyCreationFailure
+</span><span class="uncovered1"><a name="line60"></a> 60     flash.now[:error] = 'Redmine could not retrieve the required information from the LDAP to create your account. Please, contact your Redmine administrator.'
+</span><span class="marked0"><a name="line61"></a> 61   end
+</span><span class="inferred1"><a name="line62"></a> 62 
+</span><span class="inferred0"><a name="line63"></a> 63   # Log out current user and redirect to welcome page
+</span><span class="marked1"><a name="line64"></a> 64   def logout
+</span><span class="marked0"><a name="line65"></a> 65     cookies.delete :autologin
+</span><span class="marked1"><a name="line66"></a> 66     Token.delete_all([&quot;user_id = ? AND action = ?&quot;, User.current.id, 'autologin']) if User.current.logged?
+</span><span class="marked0"><a name="line67"></a> 67     self.logged_user = nil
+</span><span class="marked1"><a name="line68"></a> 68     redirect_to home_url
+</span><span class="inferred0"><a name="line69"></a> 69   end
+</span><span class="inferred1"><a name="line70"></a> 70   
+</span><span class="inferred0"><a name="line71"></a> 71   # Enable user to choose a new password
+</span><span class="marked1"><a name="line72"></a> 72   def lost_password
+</span><span class="marked0"><a name="line73"></a> 73     redirect_to(home_url) &amp;&amp; return unless Setting.lost_password?
+</span><span class="marked1"><a name="line74"></a> 74     if params[:token]
+</span><span class="marked0"><a name="line75"></a> 75       @token = Token.find_by_action_and_value(&quot;recovery&quot;, params[:token])
+</span><span class="marked1"><a name="line76"></a> 76       redirect_to(home_url) &amp;&amp; return unless @token and !@token.expired?
+</span><span class="marked0"><a name="line77"></a> 77       @user = @token.user
+</span><span class="marked1"><a name="line78"></a> 78       if request.post?
+</span><span class="marked0"><a name="line79"></a> 79         @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
+</span><span class="marked1"><a name="line80"></a> 80         if @user.save
+</span><span class="marked0"><a name="line81"></a> 81           @token.destroy
+</span><span class="marked1"><a name="line82"></a> 82           flash[:notice] = l(:notice_account_password_updated)
+</span><span class="marked0"><a name="line83"></a> 83           redirect_to :action =&gt; 'login'
+</span><span class="marked1"><a name="line84"></a> 84           return
+</span><span class="inferred0"><a name="line85"></a> 85         end 
+</span><span class="inferred1"><a name="line86"></a> 86       end
+</span><span class="marked0"><a name="line87"></a> 87       render :template =&gt; &quot;account/password_recovery&quot;
+</span><span class="marked1"><a name="line88"></a> 88       return
+</span><span class="inferred0"><a name="line89"></a> 89     else
+</span><span class="marked1"><a name="line90"></a> 90       if request.post?
+</span><span class="marked0"><a name="line91"></a> 91         user = User.find_by_mail(params[:mail])
+</span><span class="inferred1"><a name="line92"></a> 92         # user not found in db
+</span><span class="marked0"><a name="line93"></a> 93         flash.now[:error] = l(:notice_account_unknown_email) and return unless user
+</span><span class="inferred1"><a name="line94"></a> 94         # user uses an external authentification
+</span><span class="marked0"><a name="line95"></a> 95         flash.now[:error] = l(:notice_can_t_change_password) and return if user.auth_source_id
+</span><span class="inferred1"><a name="line96"></a> 96         # create a new token for password recovery
+</span><span class="marked0"><a name="line97"></a> 97         token = Token.new(:user =&gt; user, :action =&gt; &quot;recovery&quot;)
+</span><span class="marked1"><a name="line98"></a> 98         if token.save
+</span><span class="marked0"><a name="line99"></a> 99           Mailer.deliver_lost_password(token)
+</span><span class="marked1"><a name="line100"></a>100           flash[:notice] = l(:notice_account_lost_email_sent)
+</span><span class="marked0"><a name="line101"></a>101           redirect_to :action =&gt; 'login'
+</span><span class="marked1"><a name="line102"></a>102           return
+</span><span class="inferred0"><a name="line103"></a>103         end
+</span><span class="inferred1"><a name="line104"></a>104       end
+</span><span class="inferred0"><a name="line105"></a>105     end
+</span><span class="inferred1"><a name="line106"></a>106   end
+</span><span class="inferred0"><a name="line107"></a>107   
+</span><span class="inferred1"><a name="line108"></a>108   # User self-registration
+</span><span class="marked0"><a name="line109"></a>109   def register
+</span><span class="marked1"><a name="line110"></a>110     redirect_to(home_url) &amp;&amp; return unless Setting.self_registration?
+</span><span class="marked0"><a name="line111"></a>111     if request.get?
+</span><span class="marked1"><a name="line112"></a>112       @user = User.new(:language =&gt; Setting.default_language)
+</span><span class="inferred0"><a name="line113"></a>113     else
+</span><span class="marked1"><a name="line114"></a>114       @user = User.new(params[:user])
+</span><span class="marked0"><a name="line115"></a>115       @user.admin = false
+</span><span class="marked1"><a name="line116"></a>116       @user.login = params[:user][:login]
+</span><span class="marked0"><a name="line117"></a>117       @user.status = User::STATUS_REGISTERED
+</span><span class="marked1"><a name="line118"></a>118       @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
+</span><span class="marked0"><a name="line119"></a>119       case Setting.self_registration
+</span><span class="marked1"><a name="line120"></a>120       when '1'
+</span><span class="inferred0"><a name="line121"></a>121         # Email activation
+</span><span class="marked1"><a name="line122"></a>122         token = Token.new(:user =&gt; @user, :action =&gt; &quot;register&quot;)
+</span><span class="marked0"><a name="line123"></a>123         if @user.save and token.save
+</span><span class="marked1"><a name="line124"></a>124           Mailer.deliver_register(token)
+</span><span class="marked0"><a name="line125"></a>125           flash[:notice] = l(:notice_account_register_done)
+</span><span class="marked1"><a name="line126"></a>126           redirect_to :action =&gt; 'login'
+</span><span class="inferred0"><a name="line127"></a>127         end
+</span><span class="marked1"><a name="line128"></a>128       when '3'
+</span><span class="inferred0"><a name="line129"></a>129         # Automatic activation
+</span><span class="marked1"><a name="line130"></a>130         @user.status = User::STATUS_ACTIVE
+</span><span class="marked0"><a name="line131"></a>131         if @user.save
+</span><span class="marked1"><a name="line132"></a>132           self.logged_user = @user
+</span><span class="marked0"><a name="line133"></a>133           flash[:notice] = l(:notice_account_activated)
+</span><span class="marked1"><a name="line134"></a>134           redirect_to :controller =&gt; 'my', :action =&gt; 'account'
+</span><span class="inferred0"><a name="line135"></a>135         end
+</span><span class="inferred1"><a name="line136"></a>136       else
+</span><span class="inferred0"><a name="line137"></a>137         # Manual activation by the administrator
+</span><span class="marked1"><a name="line138"></a>138         if @user.save
+</span><span class="inferred0"><a name="line139"></a>139           # Sends an email to the administrators
+</span><span class="marked1"><a name="line140"></a>140           Mailer.deliver_account_activation_request(@user)
+</span><span class="marked0"><a name="line141"></a>141           flash[:notice] = l(:notice_account_pending)
+</span><span class="marked1"><a name="line142"></a>142           redirect_to :action =&gt; 'login'
+</span><span class="inferred0"><a name="line143"></a>143         end
+</span><span class="inferred1"><a name="line144"></a>144       end
+</span><span class="inferred0"><a name="line145"></a>145     end
+</span><span class="inferred1"><a name="line146"></a>146   end
+</span><span class="inferred0"><a name="line147"></a>147   
+</span><span class="inferred1"><a name="line148"></a>148   # Token based account activation
+</span><span class="marked0"><a name="line149"></a>149   def activate
+</span><span class="marked1"><a name="line150"></a>150     redirect_to(home_url) &amp;&amp; return unless Setting.self_registration? &amp;&amp; params[:token]
+</span><span class="marked0"><a name="line151"></a>151     token = Token.find_by_action_and_value('register', params[:token])
+</span><span class="marked1"><a name="line152"></a>152     redirect_to(home_url) &amp;&amp; return unless token and !token.expired?
+</span><span class="marked0"><a name="line153"></a>153     user = token.user
+</span><span class="marked1"><a name="line154"></a>154     redirect_to(home_url) &amp;&amp; return unless user.status == User::STATUS_REGISTERED
+</span><span class="marked0"><a name="line155"></a>155     user.status = User::STATUS_ACTIVE
+</span><span class="marked1"><a name="line156"></a>156     if user.save
+</span><span class="marked0"><a name="line157"></a>157       token.destroy
+</span><span class="marked1"><a name="line158"></a>158       flash[:notice] = l(:notice_account_activated)
+</span><span class="inferred0"><a name="line159"></a>159     end
+</span><span class="marked1"><a name="line160"></a>160     redirect_to :action =&gt; 'login'
+</span><span class="inferred0"><a name="line161"></a>161   end
+</span><span class="inferred1"><a name="line162"></a>162   
+</span><span class="marked0"><a name="line163"></a>163 private
+</span><span class="marked1"><a name="line164"></a>164   def logged_user=(user)
+</span><span class="marked0"><a name="line165"></a>165     if user &amp;&amp; user.is_a?(User)
+</span><span class="marked1"><a name="line166"></a>166       User.current = user
+</span><span class="marked0"><a name="line167"></a>167       session[:user_id] = user.id
+</span><span class="inferred1"><a name="line168"></a>168     else
+</span><span class="marked0"><a name="line169"></a>169       User.current = User.anonymous
+</span><span class="marked1"><a name="line170"></a>170       session[:user_id] = nil
+</span><span class="inferred0"><a name="line171"></a>171     end
+</span><span class="marked1"><a name="line172"></a>172   end
+</span><span class="inferred0"><a name="line173"></a>173 end
+</span></pre><hr/>
+    <p>Generated using the <a href='http://eigenclass.org/hiki.rb?rcov'>rcov code coverage analysis tool for Ruby</a>
+   version 0.8.1.2.</p>
+<p><a href='http://validator.w3.org/check/referer'><img src='http://www.w3.org/Icons/valid-xhtml10' height='31' alt='Valid XHTML 1.0!' width='88'/>
+        </a>
+      <a href='http://jigsaw.w3.org/css-validator/check/referer'><img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Valid CSS!' style='border:0;width:88px;height:31px'/>
+        </a>
+      </p>
+    </body>
+  </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/fixtures/html/index.html	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,306 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'><head><title>C0 code coverage information</title>
+    <style type='text/css'>body { background-color: rgb(240, 240, 245); }</style>
+    <style type='text/css'>span.cross-ref-title {
+ font-size: 140%;
+}
+span.cross-ref a {
+ text-decoration: none;
+}
+span.cross-ref {
+ background-color:#f3f7fa;
+ border: 1px dashed #333;
+ margin: 1em;
+ padding: 0.5em;
+ overflow: hidden;
+}
+a.crossref-toggle {
+ text-decoration: none;
+}
+span.marked0 {
+ background-color: rgb(185, 210, 200);
+ display: block;
+}
+span.marked1 {
+ background-color: rgb(190, 215, 205);
+ display: block;
+}
+span.inferred0 {
+ background-color: rgb(175, 200, 200);
+ display: block;
+}
+span.inferred1 {
+ background-color: rgb(180, 205, 205);
+ display: block;
+}
+span.uncovered0 {
+ background-color: rgb(225, 110, 110);
+ display: block;
+}
+span.uncovered1 {
+ background-color: rgb(235, 120, 120);
+ display: block;
+}
+span.overview {
+ border-bottom: 8px solid black;
+}
+div.overview {
+ border-bottom: 8px solid black;
+}
+body {
+ font-family: verdana, arial, helvetica;
+}
+div.footer {
+ font-size: 68%;
+ margin-top: 1.5em;
+}
+h1, h2, h3, h4, h5, h6 {
+ margin-bottom: 0.5em;
+}
+h5 {
+ margin-top: 0.5em;
+}
+.hidden {
+ display: none;
+}
+div.separator {
+ height: 10px;
+}
+/* Commented out for better readability, esp. on IE */
+/*
+table tr td, table tr th {
+ font-size: 68%;
+}
+td.value table tr td {
+ font-size: 11px;
+}
+*/
+table.percent_graph {
+ height: 12px;
+ border: #808080 1px solid;
+ empty-cells: show;
+}
+table.percent_graph td.covered {
+ height: 10px;
+ background: #00f000;
+}
+table.percent_graph td.uncovered {
+ height: 10px;
+ background: #e00000;
+}
+table.percent_graph td.NA {
+ height: 10px;
+ background: #eaeaea;
+}
+table.report {
+ border-collapse: collapse;
+ width: 100%;
+}
+table.report td.heading {
+ background: #dcecff;
+ border: #d0d0d0 1px solid;
+ font-weight: bold;
+ text-align: center;
+}
+table.report td.heading:hover {
+ background: #c0ffc0;
+}
+table.report td.text {
+ border: #d0d0d0 1px solid;
+}
+table.report td.value,
+table.report td.lines_total,
+table.report td.lines_code {
+ text-align: right;
+ border: #d0d0d0 1px solid;
+}
+table.report tr.light {
+ background-color: rgb(240, 240, 245);
+}
+table.report tr.dark {
+ background-color: rgb(230, 230, 235);
+}
+</style>
+    <script type='text/javascript'>
+// <![CDATA[
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+    
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+  
+  // Make cross-references hidden by default
+  document.writeln( "<style type=\"text/css\">span.cross-ref { display: none }</style>" )
+  // ]]>
+</script>
+    </head>
+  <body><h3>C0 code coverage information</h3>
+    <p>Generated on Tue Jun 24 21:43:50 +0200 2008 with <a href='http://eigenclass.org/hiki/rcov'>rcov 0.8.1.2</a>
+      </p>
+    <hr/>
+    <table class='report'><thead><tr><td class='heading'>Name</td>
+      <td class='heading'>Total lines</td>
+      <td class='heading'>Lines of code</td>
+      <td class='heading'>Total coverage</td>
+      <td class='heading'>Code coverage</td>
+      </tr>
+    </thead>
+  <tbody><tr class='light'><td>TOTAL</td>
+      <td class='lines_total'><tt>13757</tt>
+        </td>
+      <td class='lines_code'><tt>9314</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>90.7%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='91'/>
+                  <td class='uncovered' width='9'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>86.9%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='87'/>
+                  <td class='uncovered' width='13'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    <tr class='dark'><td><a href='app-apis-sys_api_rb.html'>app/apis/sys_api.rb</a>
+        </td>
+      <td class='lines_total'><tt>25</tt>
+        </td>
+      <td class='lines_code'><tt>8</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>100.0%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='100'/>
+                  <td class='uncovered' width='0'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>100.0%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='100'/>
+                  <td class='uncovered' width='0'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    <tr class='light'><td><a href='app-controllers-account_controller_rb.html'>app/controllers/account_controller.rb</a>
+        </td>
+      <td class='lines_total'><tt>173</tt>
+        </td>
+      <td class='lines_code'><tt>129</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>98.8%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='99'/>
+                  <td class='uncovered' width='1'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>98.4%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='98'/>
+                  <td class='uncovered' width='2'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    <tr class='dark'><td><a href='app-controllers-admin_controller_rb.html'>app/controllers/admin_controller.rb</a>
+        </td>
+      <td class='lines_total'><tt>86</tt>
+        </td>
+      <td class='lines_code'><tt>57</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>91.9%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='92'/>
+                  <td class='uncovered' width='8'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>87.7%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='88'/>
+                  <td class='uncovered' width='12'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    <tr class='light'><td><a href='app-controllers-application_rb.html'>app/controllers/application.rb</a>
+        </td>
+      <td class='lines_total'><tt>222</tt>
+        </td>
+      <td class='lines_code'><tt>162</tt>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_total'>89.6%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='90'/>
+                  <td class='uncovered' width='10'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      <td><table cellspacing='0' cellpadding='0' align='right'><tr><td><tt class='coverage_code'>87.0%</tt>
+              &nbsp;</td>
+            <td><table cellspacing='0' class='percent_graph' cellpadding='0' width='100'><tr><td class='covered' width='87'/>
+                  <td class='uncovered' width='13'/>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+<hr/>
+    <p>Generated using the <a href='http://eigenclass.org/hiki.rb?rcov'>rcov code coverage analysis tool for Ruby</a>
+   version 0.8.1.2.</p>
+<p><a href='http://validator.w3.org/check/referer'><img src='http://www.w3.org/Icons/valid-xhtml11' height='31' alt='Valid XHTML 1.1!' width='88'/>
+        </a>
+      <a href='http://jigsaw.w3.org/css-validator/check/referer'><img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Valid CSS!' style='border:0;width:88px;height:31px'/>
+        </a>
+      </p>
+    </body>
+  </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/fixtures/html/misc/misc.html	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,1 @@
+<b>Misc file</b>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/fixtures/html/misc/misc.txt	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,1 @@
+Misc file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/functional/embedded_controller_test.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,63 @@
+# Redmine - project management software
+# Copyright (C) 2008  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class EmbeddedControllerTest < ActionController::TestCase
+  fixtures :projects, :enabled_modules, :users, :roles, :members
+  
+  def setup
+    fixtures_path = File.dirname(__FILE__) + '/../fixtures/html'
+    
+    Setting.plugin_embedded = { 'path' => fixtures_path,
+                                'index' => 'main.html overview-summary.html index.html',
+                                'extensions' => 'html png gif',
+                                'template' => '',
+                                'encoding' => '',
+                                'menu' => 'Embedded' }
+                                
+    Project.find(1).enabled_modules << EnabledModule.new(:name => 'embedded')
+    
+    anonymous = Role.anonymous
+    anonymous.permissions += [:view_embedded_doc]
+    assert anonymous.save
+  end
+  
+  def test_get_root_should_redirect_to_index_file
+    get :index, :id => 'ecookbook'
+    assert_redirected_to :path => ['index.html']
+  end
+  
+  def test_get_index_file
+    get :index, :id => 'ecookbook', :path => ['index.html']
+    assert_response :success
+    assert_template 'index'
+    assert_tag :h3, :content => 'C0 code coverage information'
+  end
+  
+  def test_get_subdirectory_file
+    get :index, :id => 'ecookbook', :path => ['misc', 'misc.html']
+    assert_response :success
+    assert_template 'index'
+    assert_tag :b, :content => 'Misc file'
+  end
+  
+  def test_get_invalid_extension_should_be_denied
+    get :index, :id => 'ecookbook', :path => ['misc', 'misc.txt']
+    assert_response 500
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/test_helper.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,38 @@
+ENV["RAILS_ENV"] ||= "test"
+require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
+require 'test_help'
+
+class Test::Unit::TestCase
+  # Transactional fixtures accelerate your tests by wrapping each test method
+  # in a transaction that's rolled back on completion.  This ensures that the
+  # test database remains unchanged so your fixtures don't have to be reloaded
+  # between every test method.  Fewer database queries means faster tests.
+  #
+  # Read Mike Clark's excellent walkthrough at
+  #   http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
+  #
+  # Every Active Record database supports transactions except MyISAM tables
+  # in MySQL.  Turn off transactional fixtures in this case; however, if you
+  # don't care one way or the other, switching from MyISAM to InnoDB tables
+  # is recommended.
+  #
+  # The only drawback to using transactional fixtures is when you actually 
+  # need to test transactions.  Since your test is bracketed by a transaction,
+  # any transactions started in your code will be automatically rolled back.
+  self.use_transactional_fixtures = true
+
+  # Instantiated fixtures are slow, but give you @david where otherwise you
+  # would need people(:david).  If you don't want to migrate your existing
+  # test cases which use the @david style and don't mind the speed hit (each
+  # instantiated fixtures translates to a database query per test method),
+  # then set this back to true.
+  self.use_instantiated_fixtures  = false
+
+  # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
+  #
+  # Note: You'll currently still have to declare fixtures explicitly in integration tests
+  # -- they do not yet inherit this setting
+  fixtures :all
+
+  # Add more helper methods to be used by all tests here...
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/plugins/embedded/test/unit/embedded_test.rb	Thu Jan 27 09:08:03 2011 +0000
@@ -0,0 +1,54 @@
+# Redmine - project management software
+# Copyright (C) 2008  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class EmbeddedTest < ActiveSupport::TestCase
+
+  def setup
+    Setting.plugin_embedded = { 'path' => '/path/to',
+                                'index' => 'main.html overview-summary.html index.html',
+                                'extensions' => 'html png gif',
+                                'template' => 'doxygen',
+                                'encoding' => '',
+                                'menu' => 'Embedded' }
+  end
+  
+  def test_available_templates
+    assert_equal ['doxygen', 'javadoc', 'rcov'], Redmine::Plugins::Embedded.available_templates
+  end
+  
+  def test_assets
+    assert_equal ['rcov.css', 'rcov.js'], Redmine::Plugins::Embedded.assets('rcov')
+  end
+  
+  def test_detect_template_from_path
+    to_test = { '/path/to/doc' => 'doxygen',
+                '/path/to/javadoc/html' => 'javadoc' }
+                
+    to_test.each { |path, template| assert_equal template, Redmine::Plugins::Embedded.detect_template_from_path(path) }
+  end
+  
+  def test_valid_extension
+    to_test = {'index.html' => true,
+               'path/to/index.html' => true,
+               'path/to/image.png' => true,
+               'path/to/something.else' => false}
+
+    to_test.each { |path, expected| assert_equal expected, Redmine::Plugins::Embedded.valid_extension?(path) }
+  end
+end